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 java.io.*;
020import java.lang.reflect.*;
021import java.nio.charset.*;
022
023import org.apache.juneau.marshall.*;
024import org.apache.juneau.marshall.parser.*;
025import org.apache.juneau.marshall.serializer.*;
026import org.apache.juneau.marshall.stream.*;
027
028/**
029 * Top-level class for a pairing of a {@link Serializer} and {@link Parser} into a single class with convenience read/write methods.
030 *
031 * <p>
032 *    The general idea is to combine a single serializer and parser inside a simplified API for reading and writing POJOs.
033 *
034 * <h5 class='figure'>Examples:</h5>
035 * <p class='bjava'>
036 *    <jc>// Using instance.</jc>
037    *    Marshaller <jv>json</jv> = <jk>new</jk> Json();
038 *    MyPojo <jv>myPojo</jv> = <jv>json</jv>.read(<jv>string</jv>, MyPojo.<jk>class</jk>);
039 *    String <jv>string</jv> = <jv>json</jv>.write(<jv>myPojo</jv>);
040 * </p>
041 * <p class='bjava'>
042 * <jc>// Using DEFAULT instance.</jc>
043 *    MyPojo <jv>myPojo</jv> = Json.<jsf>DEFAULT</jsf>.read(<jv>string</jv>, MyPojo.<jk>class</jk>);
044 *    String <jv>string</jv> = Json.<jsf>DEFAULT</jsf>.write(<jv>myPojo</jv>);
045 * </p>
046 *
047 * <h5 class='section'>See Also:</h5><ul>
048 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshallers">Marshallers</a>
049 * </ul>
050 */
051@SuppressWarnings({
052   "resource" // Cursor shortcut methods return Closeables owned by the caller; Eclipse JDT @Owning warning is by design.
053})
054public abstract class Marshaller {
055   private final Serializer s;
056   private final Parser p;
057
058   /**
059    * Constructor.
060    *
061    * @param s
062    *    The serializer to use for serializing output.
063    *    <br>Must not be <jk>null</jk>.
064    * @param p
065    *    The parser to use for parsing input.
066    *    <br>Must not be <jk>null</jk>.
067    */
068   protected Marshaller(Serializer s, Parser p) {
069      this.s = s;
070      this.p = p;
071   }
072
073   /**
074    * Returns the parser associated with this marshaller.
075    *
076    * @return The parser associated with this marshaller.
077    */
078   public Parser getParser() { return p; }
079
080   /**
081    * Returns the serializer associated with this marshaller.
082    *
083    * @return The serializer associated with this marshaller.
084    */
085   public Serializer getSerializer() { return s; }
086
087   /**
088    * Same as {@link #read(Object, Type, Type...)} except optimized for a non-parameterized class.
089    *
090    * <p>
091    * This is the preferred parse method for simple types since you don't need to cast the results.
092    *
093    * <h5 class='section'>Examples:</h5>
094    * <p class='bjava'>
095    *    Marshaller <jv>marshaller</jv>  = Json.<jsf>DEFAULT</jsf>;
096    *
097    *    <jc>// Parse into a string.</jc>
098    *    String <jv>string</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, String.<jk>class</jk>);
099    *
100    *    <jc>// Parse into a bean.</jc>
101    *    MyBean <jv>bean</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, MyBean.<jk>class</jk>);
102    *
103    *    <jc>// Parse into a bean array.</jc>
104    *    MyBean[] <jv>beanArray</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, MyBean[].<jk>class</jk>);
105    *
106    *    <jc>// Parse into a linked-list of objects.</jc>
107    *    List <jv>list</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>);
108    *
109    *    <jc>// Parse into a map of object keys/values.</jc>
110    *    Map <jv>map</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, TreeMap.<jk>class</jk>);
111    * </p>
112    *
113    * @param <T> The class type of the object being created.
114    * @param input
115    *    The input.
116    *    <br>Character-based parsers can handle the following input class types:
117    *    <ul>
118    *       <li><jk>null</jk>
119    *       <li>{@link Reader}
120    *       <li>{@link CharSequence}
121    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
122    *          {@link org.apache.juneau.marshall.parser.ReaderParser.Builder#streamCharset(Charset) ReaderParser.Builder#streamCharset(Charset)} property value).
123    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
124    *          {@link org.apache.juneau.marshall.parser.ReaderParser.Builder#streamCharset(Charset) ReaderParser.Builder#streamCharset(Charset)} property value).
125    *       <li>{@link File} containing system encoded text.
126    *    </ul>
127    *    <br>Stream-based parsers can handle the following input class types:
128    *    <ul>
129    *       <li><jk>null</jk>
130    *       <li>{@link InputStream}
131    *       <li><code><jk>byte</jk>[]</code>
132    *       <li>{@link File}
133    *       <li>{@link CharSequence} containing encoded bytes according to the {@link org.apache.juneau.marshall.parser.InputStreamParser.Builder#binaryFormat(BinaryFormat) InputStreamParser.Builder#binaryFormat(BinaryFormat)} setting.
134    *    </ul>
135    * @param type The object type to create.
136    * @return The parsed object.
137    * @throws ParseException Malformed input encountered.
138    * @throws IOException Thrown by underlying stream.
139    */
140   public final <T> T read(Object input, Class<T> type) throws ParseException, IOException {
141      return p.read(input, type);
142   }
143
144   /**
145    * Parses input into the specified object type.
146    *
147    * <p>
148    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
149    *
150    * <h5 class='section'>Examples:</h5>
151    * <p class='bjava'>
152    *    Marshaller <jv>marshaller</jv> = Json.<jsf>DEFAULT</jsf>;
153    *
154    *    <jc>// Parse into a linked-list of strings.</jc>
155    *    List <jv>list1</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
156    *
157    *    <jc>// Parse into a linked-list of beans.</jc>
158    *    List <jv>list2</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
159    *
160    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
161    *    List <jv>list3</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
162    *
163    *    <jc>// Parse into a map of string keys/values.</jc>
164    *    Map <jv>map1</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
165    *
166    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
167    *    Map <jv>map2</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
168    * </p>
169    *
170    * <p>
171    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
172    *
173    * <p>
174    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
175    *
176    * <p>
177    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
178    *
179    * <h5 class='section'>Notes:</h5><ul>
180    *    <li class='note'>
181    *       Use the {@link #read(Object, Class)} method instead if you don't need a parameterized map/collection.
182    * </ul>
183    *
184    * @param <T> The class type of the object to create.
185    * @param input
186    *    The input.
187    *    <br>Character-based parsers can handle the following input class types:
188    *    <ul>
189    *       <li><jk>null</jk>
190    *       <li>{@link Reader}
191    *       <li>{@link CharSequence}
192    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
193    *          {@link org.apache.juneau.marshall.parser.ReaderParser.Builder#streamCharset(Charset) ReaderParser.Builder#streamCharset(Charset)} property value).
194    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
195    *          {@link org.apache.juneau.marshall.parser.ReaderParser.Builder#streamCharset(Charset) ReaderParser.Builder#streamCharset(Charset)} property value).
196    *       <li>{@link File} containing system encoded text.
197    *    </ul>
198    *    <br>Stream-based parsers can handle the following input class types:
199    *    <ul>
200    *       <li><jk>null</jk>
201    *       <li>{@link InputStream}
202    *       <li><code><jk>byte</jk>[]</code>
203    *       <li>{@link File}
204    *       <li>{@link CharSequence} containing encoded bytes according to the {@link org.apache.juneau.marshall.parser.InputStreamParser.Builder#binaryFormat(BinaryFormat) InputStreamParser.Builder#binaryFormat(BinaryFormat)} setting.
205    *    </ul>
206    * @param type
207    *    The object type to create.
208    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
209    * @param args
210    *    The type arguments of the class if it's a collection or map.
211    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
212    *    <br>Ignored if the main type is not a map or collection.
213    * @return The parsed object.
214    * @throws ParseException Malformed input encountered.
215    * @throws IOException Thrown by underlying stream.
216    * @see MarshallingSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
217    */
218   public final <T> T read(Object input, Type type, Type...args) throws ParseException, IOException {
219      return p.read(input, type, args);
220   }
221
222   /**
223    * Serializes a POJO to the specified output stream or writer.
224    *
225    * <p>
226    * Equivalent to calling <c>serializer.createSession().write(o, output);</c>
227    *
228    * @param object The object to serialize.
229    * @param output
230    *    The output object.
231    *    <br>Character-based serializers can handle the following output class types:
232    *    <ul>
233    *       <li>{@link Writer}
234    *       <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream.
235    *       <li>{@link File} - Output will be written as system-default encoded stream.
236    *       <li>{@link StringBuilder} - Output will be written to the specified string builder.
237    *    </ul>
238    *    <br>Stream-based serializers can handle the following output class types:
239    *    <ul>
240    *       <li>{@link OutputStream}
241    *       <li>{@link File}
242    *    </ul>
243    * @throws SerializeException If a problem occurred trying to convert the output.
244    * @throws IOException Thrown by underlying stream.
245    */
246   public final void write(Object object, Object output) throws SerializeException, IOException {
247      s.write(object, output);
248   }
249
250   /**
251    * Opens a low-level {@link TokenReader} cursor over the specified input.
252    *
253    * <p>
254    * Shortcut for <c>((TokenReadable)getParser()).readTokens(<jv>input</jv>)</c>.  See
255    * {@link TokenReader} for the cursor contract.
256    *
257    * <h5 class='section'>Notes:</h5><ul>
258    *    <li class='note'>This capability depends on the underlying parser.  Formats whose parser
259    *       does not implement {@link TokenReadable} (the structural-token role) yield a
260    *       {@link ClassCastException}.
261    * </ul>
262    *
263    * @param input The input.  Accepts {@link Reader}, {@link CharSequence}, {@link InputStream},
264    *    <code><jk>byte</jk>[]</code>, or {@link File}.
265    * @return A new {@link TokenReader} cursor.
266    * @throws IOException If a problem occurred opening the underlying input.
267    */
268   public TokenReader readTokens(Object input) throws IOException {
269      return ((TokenReadable) getParser()).readTokens(input);
270   }
271
272   /**
273    * Opens a low-level push generator that emits structural events one at a time.
274    *
275    * <p>
276    * Shortcut for <c>((TokenWritable)getSerializer()).writeTokens(<jv>output</jv>)</c>.  See
277    * {@link TokenWriter} for the generator contract.
278    *
279    * <h5 class='section'>Notes:</h5><ul>
280    *    <li class='note'>This capability depends on the underlying serializer.  Formats whose
281    *       serializer does not implement {@link TokenWritable} (the structural-token role) yield a
282    *       {@link ClassCastException}.
283    * </ul>
284    *
285    * @param output The output.  Accepts {@link Writer}, {@link OutputStream}, {@link File}, or
286    *    {@link StringBuilder}.
287    * @return A new {@link TokenWriter}.
288    * @throws IOException If the output type is not supported or could not be opened.
289    */
290   public TokenWriter writeTokens(Object output) throws IOException {
291      return ((TokenWritable) getSerializer()).writeTokens(output);
292   }
293
294   /**
295    * Opens a low-level {@link RecordReader} cursor that yields each top-level value as a record.
296    *
297    * <p>
298    * Shortcut for <c>((RecordReadable)getParser()).readRecords(<jv>input</jv>)</c>.  See
299    * {@link RecordReader} for the cursor contract.
300    *
301    * <h5 class='section'>Notes:</h5><ul>
302    *    <li class='note'>This capability depends on the underlying parser.  Formats whose parser
303    *       does not implement {@link RecordReadable} yield a {@link ClassCastException}.
304    * </ul>
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 RecordReader} cursor.
309    * @throws IOException If a problem occurred opening the underlying input.
310    */
311   public RecordReader readRecords(Object input) throws IOException {
312      return ((RecordReadable) getParser()).readRecords(input);
313   }
314
315   /**
316    * Opens a low-level {@link RecordWriter} cursor that emits each whole value as a record.
317    *
318    * <p>
319    * Shortcut for <c>((RecordWritable)getSerializer()).writeRecords(<jv>output</jv>)</c>.  See
320    * {@link RecordWriter} for the cursor contract.
321    *
322    * <h5 class='section'>Notes:</h5><ul>
323    *    <li class='note'>This capability depends on the underlying serializer.  Formats whose
324    *       serializer does not implement {@link RecordWritable} yield a {@link ClassCastException}.
325    * </ul>
326    *
327    * @param output The output.  Accepts {@link Writer}, {@link OutputStream}, {@link File}, or
328    *    {@link StringBuilder}.
329    * @return A new {@link RecordWriter} cursor.
330    * @throws IOException If a problem occurred opening the underlying output.
331    */
332   public RecordWriter writeRecords(Object output) throws IOException {
333      return ((RecordWritable) getSerializer()).writeRecords(output);
334   }
335
336   /**
337    * Opens a {@link RecordReader} that yields each element of a top-level wire array as a
338    * separate record.
339    *
340    * <p>
341    * Shortcut for <c>((ArrayRecordReadable)getParser()).readArrayRecords(<jv>input</jv>)</c>.
342    *
343    * <h5 class='section'>Notes:</h5><ul>
344    *    <li class='note'>This capability depends on the underlying parser.  Formats whose parser
345    *       does not implement {@link ArrayRecordReadable} yield a {@link ClassCastException}.
346    * </ul>
347    *
348    * @param input The input.  Accepts {@link Reader}, {@link CharSequence}, {@link InputStream},
349    *    <code><jk>byte</jk>[]</code>, or {@link File}.
350    * @return A new element-streamed {@link RecordReader} cursor.
351    * @throws IOException If a problem occurred opening the underlying input.
352    */
353   public RecordReader readArrayRecords(Object input) throws IOException {
354      return ((ArrayRecordReadable) getParser()).readArrayRecords(input);
355   }
356
357   /**
358    * Opens a {@link RecordWriter} that wraps each written value as one element of a top-level
359    * wire array.
360    *
361    * <p>
362    * Shortcut for <c>((ArrayRecordWritable)getSerializer()).writeArrayRecords(<jv>output</jv>)</c>.
363    *
364    * <h5 class='section'>Notes:</h5><ul>
365    *    <li class='note'>This capability depends on the underlying serializer.  Formats whose
366    *       serializer does not implement {@link ArrayRecordWritable} yield a
367    *       {@link ClassCastException}.
368    * </ul>
369    *
370    * @param output The output.  Accepts {@link Writer}, {@link OutputStream}, {@link File}, or
371    *    {@link StringBuilder}.
372    * @return A new element-streamed {@link RecordWriter} cursor.
373    * @throws IOException If a problem occurred opening the underlying output.
374    */
375   public RecordWriter writeArrayRecords(Object output) throws IOException {
376      return ((ArrayRecordWritable) getSerializer()).writeArrayRecords(output);
377   }
378}