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.marshaller;
018
019import org.apache.juneau.marshall.jcs.*;
020import org.apache.juneau.marshall.json.*;
021import java.io.*;
022import java.lang.reflect.*;
023import org.apache.juneau.marshall.parser.*;
024import org.apache.juneau.marshall.serializer.*;
025import org.apache.juneau.marshall.stream.*;
026
027/**
028 * A pairing of a {@link JcsSerializer} and {@link JsonParser} into a single class with
029 * convenience to/of methods.
030 *
031 * <p>
032 *    Produces canonical JSON per <a class="doclink" href="https://www.rfc-editor.org/rfc/rfc8785">RFC 8785</a>.
033 *    Parsing uses the standard {@link JsonParser} since JCS output is valid JSON.
034 * </p>
035 *
036 * <h5 class='figure'>Examples:</h5>
037 * <p class='bjava'>
038 *    <jc>// Using static convenience methods.</jc>
039 *    String <jv>s</jv> = Jcs.<jsm>of</jsm>(<jv>myBean</jv>);
040 *    MyBean <jv>b</jv> = Jcs.<jsm>to</jsm>(<jv>s</jv>, MyBean.<jk>class</jk>);
041 * </p>
042 * <p class='bjava'>
043 *    <jc>// Using instance.</jc>
044 *    Jcs <jv>jcs</jv> = <jk>new</jk> Jcs();
045 *    String <jv>s</jv> = <jv>jcs</jv>.write(<jv>myBean</jv>);
046 *    MyBean <jv>b</jv> = <jv>jcs</jv>.read(<jv>s</jv>, MyBean.<jk>class</jk>);
047 * </p>
048 *
049 * <h5 class='figure'>Example output (bean with name/age):</h5>
050 * <p class='bjson'>
051 *    {<jok>"age"</jok>:<jov>30</jov>,<jok>"name"</jok>:<jov>"Alice"</jov>}
052 * </p>
053 *
054 * <h5 class='section'>Notes:</h5><ul>
055 *    <li class='note'>
056 *       {@link java.math.BigDecimal} and {@link java.math.BigInteger} values beyond IEEE 754 double
057 *       precision range will lose precision or throw during serialization.
058 *    <li class='note'>
059 *       {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, and {@link Double#NEGATIVE_INFINITY}
060 *       are not permitted and will throw during serialization.
061 * </ul>
062 *
063 * <p class='bjava'>
064 * <jc>// Using static shortcuts.</jc>
065 *    MyPojo <jv>myPojo</jv> = Jcs.<jsm>to</jsm>(<jv>string</jv>, MyPojo.<jk>class</jk>);
066 *    String <jv>string</jv> = Jcs.<jsm>of</jsm>(<jv>myPojo</jv>);
067 * </p>
068 *
069 * <h5 class='section'>See Also:</h5><ul>
070 *    <li class='link'><a class="doclink" href="https://www.rfc-editor.org/rfc/rfc8785">RFC 8785 — JSON Canonicalization Scheme</a>
071 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Jcs">JCS</a>
072 *    <li class='jc'>{@link JcsSerializer}
073 *    <li class='jc'>{@link JsonParser}
074 * </ul>
075 */
076@SuppressWarnings({
077   "resource" // Cursor shortcut methods return Closeables owned by the caller; Eclipse JDT @Owning warning is by design.
078})
079public class Jcs extends CharMarshaller {
080
081   /** Default reusable instance. */
082   public static final Jcs DEFAULT = new Jcs();
083
084   /**
085    * Serializes a POJO to a <c>String</c> using the {@link #DEFAULT} marshaller.
086    *
087    * <p>
088    * A shortcut for calling <c><jsf>DEFAULT</jsf>.write(<jv>object</jv>)</c>.
089    *
090    * @param object The object to serialize.
091    * @return The serialized object.
092    * @throws SerializeException If a problem occurred trying to convert the output.
093    */
094   public static String of(Object object) throws SerializeException {
095      return DEFAULT.write(object);
096   }
097
098   /**
099    * Parses an input into the specified object type using the {@link #DEFAULT} marshaller.
100    *
101    * <p>
102    * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>)</c>.
103    *
104    * @param <T> The class type of the object being created.
105    * @param input The input.
106    * @param type The object type to create.
107    * @return The parsed object.
108    * @throws ParseException Malformed input encountered.
109    */
110   public static <T> T to(String input, Class<T> type) throws ParseException {
111      return DEFAULT.read(input, type);
112   }
113
114   /**
115    * Parses an input into the specified parameterized object type using the {@link #DEFAULT} marshaller.
116    *
117    * <p>
118    * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>, <jv>args</jv>)</c>.
119    *
120    * @param <T> The class type of the object to create.
121    * @param input The input.
122    * @param type The object type to create.
123    * @param args The type arguments of the class if it's a collection or map.
124    * @return The parsed object.
125    * @throws ParseException Malformed input encountered.
126    */
127   public static <T> T to(String input, Type type, Type... args) throws ParseException {
128      return DEFAULT.read(input, type, args);
129   }
130
131   /**
132    * Parses the contents of a {@link Reader} into the specified object type using the {@link #DEFAULT} marshaller.
133    *
134    * <p>
135    * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>)</c> that catches any
136    * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link ParseException}, so the
137    * caller is not burdened with a checked exception.
138    *
139    * @param <T> The class type of the object being created.
140    * @param input The input reader.
141    * @param type The object type to create.
142    * @return The parsed object.
143    * @throws ParseException Malformed input encountered or an I/O error occurred on the underlying stream.
144    */
145   public static <T> T to(Reader input, Class<T> type) throws ParseException {
146      try {
147         return DEFAULT.read(input, type);
148      } catch (IOException e) {
149         throw new ParseException(e);
150      }
151   }
152
153   /**
154    * Parses the contents of a {@link Reader} into the specified parameterized object type using the {@link #DEFAULT} marshaller.
155    *
156    * <p>
157    * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>, <jv>args</jv>)</c> that catches any
158    * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link ParseException}, so the
159    * caller is not burdened with a checked exception.
160    *
161    * @param <T> The class type of the object to create.
162    * @param input The input reader.
163    * @param type The object type to create.
164    * @param args The type arguments of the class if it's a collection or map.
165    * @return The parsed object.
166    * @throws ParseException Malformed input encountered or an I/O error occurred on the underlying stream.
167    */
168   public static <T> T to(Reader input, Type type, Type... args) throws ParseException {
169      try {
170         return DEFAULT.read(input, type, args);
171      } catch (IOException e) {
172         throw new ParseException(e);
173      }
174   }
175
176   /**
177    * Serializes a POJO to the specified {@link Writer} using the {@link #DEFAULT} marshaller.
178    *
179    * <p>
180    * A shortcut for calling <c><jsf>DEFAULT</jsf>.write(<jv>object</jv>, <jv>output</jv>)</c> that catches any
181    * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link SerializeException}, so the
182    * caller is not burdened with a checked exception.
183    *
184    * @param object The object to serialize.
185    * @param output The writer to serialize to.
186    * @throws SerializeException If a problem occurred trying to convert the output or an I/O error occurred on the underlying stream.
187    */
188   public static void of(Object object, Writer output) throws SerializeException {
189      try {
190         DEFAULT.write(object, output);
191      } catch (IOException e) {
192         throw new SerializeException(e);
193      }
194   }
195
196   /**
197    * Opens a low-level {@link TokenReader} cursor over the specified input using the {@link #DEFAULT} marshaller.
198    *
199    * <p>
200    * A shortcut for calling <c><jsf>DEFAULT</jsf>.readTokens(<jv>input</jv>)</c>.
201    *
202    * @param input The input.
203    * @return A new {@link TokenReader}.
204    * @throws IOException If a problem occurred opening the underlying input.
205    */
206   public static TokenReader toTokens(Object input) throws IOException {
207      return DEFAULT.readTokens(input);
208   }
209
210   /**
211    * Opens a low-level {@link TokenWriter} generator over the specified output using the {@link #DEFAULT} marshaller.
212    *
213    * <p>
214    * A shortcut for calling <c><jsf>DEFAULT</jsf>.writeTokens(<jv>output</jv>)</c>.
215    *
216    * @param output The output.
217    * @return A new {@link TokenWriter}.
218    * @throws IOException If a problem occurred opening the underlying output.
219    */
220   public static TokenWriter ofTokens(Object output) throws IOException {
221      return DEFAULT.writeTokens(output);
222   }
223
224   /**
225    * Opens a low-level {@link RecordReader} cursor over the specified input using the {@link #DEFAULT} marshaller.
226    *
227    * <p>
228    * A shortcut for calling <c><jsf>DEFAULT</jsf>.readRecords(<jv>input</jv>)</c>.
229    *
230    * @param input The input.
231    * @return A new {@link RecordReader}.
232    * @throws IOException If a problem occurred opening the underlying input.
233    */
234   public static RecordReader toRecords(Object input) throws IOException {
235      return DEFAULT.readRecords(input);
236   }
237
238   /**
239    * Opens a low-level {@link RecordWriter} cursor over the specified output using the {@link #DEFAULT} marshaller.
240    *
241    * <p>
242    * A shortcut for calling <c><jsf>DEFAULT</jsf>.writeRecords(<jv>output</jv>)</c>.
243    *
244    * @param output The output.
245    * @return A new {@link RecordWriter}.
246    * @throws IOException If a problem occurred opening the underlying output.
247    */
248   public static RecordWriter ofRecords(Object output) throws IOException {
249      return DEFAULT.writeRecords(output);
250   }
251
252   /**
253    * Opens a {@link RecordReader} that yields each element of a top-level wire array using the {@link #DEFAULT} marshaller.
254    *
255    * <p>
256    * A shortcut for calling <c><jsf>DEFAULT</jsf>.readArrayRecords(<jv>input</jv>)</c>.
257    *
258    * @param input The input.
259    * @return A new {@link RecordReader}.
260    * @throws IOException If a problem occurred opening the underlying input.
261    */
262   public static RecordReader toArrayRecords(Object input) throws IOException {
263      return DEFAULT.readArrayRecords(input);
264   }
265
266   /**
267    * Opens a {@link RecordWriter} that wraps each written value as one element of a top-level wire array using the {@link #DEFAULT} marshaller.
268    *
269    * <p>
270    * A shortcut for calling <c><jsf>DEFAULT</jsf>.writeArrayRecords(<jv>output</jv>)</c>.
271    *
272    * @param output The output.
273    * @return A new {@link RecordWriter}.
274    * @throws IOException If a problem occurred opening the underlying output.
275    */
276   public static RecordWriter ofArrayRecords(Object output) throws IOException {
277      return DEFAULT.writeArrayRecords(output);
278   }
279
280   /**
281    * Constructor.
282    *
283    * <p>
284    * Uses {@link JcsSerializer#DEFAULT} and {@link JsonParser#DEFAULT}.
285    */
286   public Jcs() {
287      this(JcsSerializer.DEFAULT, JsonParser.DEFAULT);
288   }
289
290   /**
291    * Constructor.
292    *
293    * @param s The serializer to use for serializing output.
294    * @param p The parser to use for parsing input.
295    */
296   public Jcs(JcsSerializer s, JsonParser p) {
297      super(s, p);
298   }
299}