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