001package org.apache.juneau.marshall;
002// ***************************************************************************************************************************
003// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
004// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
005// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
006// * with the License.  You may obtain a copy of the License at                                                              *
007// *                                                                                                                         *
008// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
009// *                                                                                                                         *
010// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
011// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
012// * specific language governing permissions and limitations under the License.                                              *
013// ***************************************************************************************************************************
014
015import java.io.*;
016import java.lang.reflect.*;
017import java.text.*;
018
019import org.apache.juneau.*;
020import org.apache.juneau.parser.*;
021import org.apache.juneau.parser.ParseException;
022import org.apache.juneau.serializer.*;
023
024/**
025 * Top-level class for a pairing of a {@link Serializer} and {@link Parser} into a single class with convenience read/write methods.
026 *
027 * <p>
028 *    The general idea is to combine a single serializer and parser inside a simplified API for reading and writing POJOs.
029 *
030 * <h5 class='figure'>Examples:</h5>
031 * <p class='bcode w800'>
032 *    <jc>// Using instance.</jc>
033 *    Marshall json = <jk>new</jk> Json();
034 *    MyPojo myPojo = json.read(string, MyPojo.<jk>class</jk>);
035 *    String string = json.write(myPojo);
036 * </p>
037 * <p class='bcode w800'>
038 * <jc>// Using DEFAULT instance.</jc>
039 *    MyPojo myPojo = Json.<jsf>DEFAULT</jsf>.read(string, MyPojo.<jk>class</jk>);
040 *    String string = Json.<jsf>DEFAULT</jsf>.write(myPojo);
041 * </p>
042 *
043 * <ul class='seealso'>
044 *    <li class='link'>{@doc juneau-marshall.Marshalls}
045 * </ul>
046 */
047public abstract class Marshall {
048
049   private final Serializer s;
050   private final Parser p;
051
052   /**
053    * Constructor.
054    *
055    * @param s
056    *    The serializer to use for serializing output.
057    *    <br>Must not be <jk>null</jk>.
058    * @param p
059    *    The parser to use for parsing input.
060    *    <br>Must not be <jk>null</jk>.
061    */
062   protected Marshall(Serializer s, Parser p) {
063      this.s = s;
064      this.p = p;
065   }
066
067   /**
068    * Returns the serializer associated with this marshall.
069    *
070    * @return The serializer associated with this marshall.
071    */
072   public Serializer getSerializer() {
073      return s;
074   }
075
076   /**
077    * Returns the parser associated with this marshall.
078    *
079    * @return The parser associated with this marshall.
080    */
081   public Parser getParser() {
082      return p;
083   }
084
085   /**
086    * Serializes a POJO directly to either a <c>String</c> or <code><jk>byte</jk>[]</code> depending on the serializer type.
087    *
088    * @param o The object to serialize.
089    * @return
090    *    The serialized object.
091    *    <br>Character-based serializers will return a <c>String</c>
092    *    <br>Stream-based serializers will return a <code><jk>byte</jk>[]</code>
093    * @throws SerializeException If a problem occurred trying to convert the output.
094    */
095   public Object write(Object o) throws SerializeException {
096      return s.createSession().serialize(o);
097   }
098
099   /**
100    * Serializes a POJO to the specified output stream or writer.
101    *
102    * <p>
103    * Equivalent to calling <c>serializer.createSession().serialize(o, output);</c>
104    *
105    * @param o The object to serialize.
106    * @param output
107    *    The output object.
108    *    <br>Character-based serializers can handle the following output class types:
109    *    <ul>
110    *       <li>{@link Writer}
111    *       <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream.
112    *       <li>{@link File} - Output will be written as system-default encoded stream.
113    *       <li>{@link StringBuilder} - Output will be written to the specified string builder.
114    *    </ul>
115    *    <br>Stream-based serializers can handle the following output class types:
116    *    <ul>
117    *       <li>{@link OutputStream}
118    *       <li>{@link File}
119    *    </ul>
120    * @throws SerializeException If a problem occurred trying to convert the output.
121    * @throws IOException Thrown by underlying stream.
122    */
123   public final void write(Object o, Object output) throws SerializeException, IOException {
124      s.createSession().serialize(o, output);
125   }
126
127   /**
128    * Convenience method for serializing an object to a String.
129    *
130    * <p>
131    * For writer-based serializers, this is identical to calling {@link Serializer#serialize(Object)}.
132    * <br>For stream-based serializers, this converts the returned byte array to a string based on
133    * the {@link OutputStreamSerializer#OSSERIALIZER_binaryFormat} setting.
134    *
135    * @param o The object to serialize.
136    * @return The output serialized to a string.
137    */
138   public final String toString(Object o) {
139      try {
140         return s.serializeToString(o);
141      } catch (Exception e) {
142         throw new RuntimeException(e);
143      }
144   }
145
146
147   /**
148    * Convenience method for calling <c>System.out.println(...)</c> on the specified object after calling {@link #toString(Object)}.
149    *
150    * @param o The object to serialize and then send to the console.
151    * @return This object (for method chaining).
152    */
153   public final Marshall println(Object o) {
154      System.out.println(toString(o));
155      return this;
156   }
157
158   /**
159    * Prints a message with arguments to {@link System#out}.
160    *
161    * <p>
162    * Arguments are automatically converted to strings using this marshaller.
163    *
164    * <p>
165    * Useful for debug messages.
166    *
167    * <h5 class='figure'>Example:</h5>
168    * <p class='bcode'>
169    *    SimpleJson.<jsf>DEFAULT</jsf>.out(<js>"myPojo={0}"</js>, myPojo);
170    * </p>
171    *
172    * @param msg The {@link MessageFormat}-styled message.
173    * @param args The arguments sent to the the formatter after running them through this marshaller.
174    * @return This object (for method chaining).
175    */
176   public final Marshall out(String msg, Object...args) {
177      System.out.println(format(msg, args));
178      return this;
179   }
180
181   /**
182    * Prints a message with arguments to {@link System#err}.
183    *
184    * <p>
185    * Arguments are automatically converted to strings using this marshaller.
186    *
187    * <p>
188    * Useful for debug messages.
189    *
190    * <h5 class='figure'>Example:</h5>
191    * <p class='bcode'>
192    *    SimpleJson.<jsf>DEFAULT</jsf>.err(<js>"myPojo={0}"</js>, myPojo);
193    * </p>
194    *
195    * @param msg The {@link MessageFormat}-styled message.
196    * @param args The arguments sent to the the formatter after running them through this marshaller.
197    * @return This object (for method chaining).
198    */
199   public final Marshall err(String msg, Object...args) {
200      System.err.println(format(msg, args));
201      return this;
202   }
203
204   /**
205    * Formats a message with arguments.
206    *
207    * <p>
208    * Arguments are automatically converted to strings using this marshaller.
209    *
210    * <p>
211    * Useful for debug messages.
212    *
213    * <h5 class='figure'>Example:</h5>
214    * <p class='bcode'>
215    *    String msg = SimpleJson.<jsf>DEFAULT</jsf>.format(<js>"myPojo={0}"</js>, myPojo);
216    * </p>
217    *
218    * @param msg The {@link MessageFormat}-styled message.
219    * @param args The arguments sent to the the formatter after running them through this marshaller.
220    * @return This object (for method chaining).
221    */
222   public final String format(String msg, Object...args) {
223      for (int i = 0; i < args.length; i++)
224         args[i] = toString(args[i]);
225      return MessageFormat.format(msg, args);
226   }
227
228   /**
229    * Parses input into the specified object type.
230    *
231    * <p>
232    * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps).
233    *
234    * <h5 class='section'>Examples:</h5>
235    * <p class='bcode w800'>
236    *    Marshall m = Json.<jsf>DEFAULT</jsf>;
237    *
238    *    <jc>// Parse into a linked-list of strings.</jc>
239    *    List l = m.read(json, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
240    *
241    *    <jc>// Parse into a linked-list of beans.</jc>
242    *    List l = m.read(json, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>);
243    *
244    *    <jc>// Parse into a linked-list of linked-lists of strings.</jc>
245    *    List l = m.read(json, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>);
246    *
247    *    <jc>// Parse into a map of string keys/values.</jc>
248    *    Map m = m.read(json, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>);
249    *
250    *    <jc>// Parse into a map containing string keys and values of lists containing beans.</jc>
251    *    Map m = m.read(json, TreeMap.<jk>class</jk>, String.<jk>class</jk>, List.<jk>class</jk>, MyBean.<jk>class</jk>);
252    * </p>
253    *
254    * <p>
255    * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type.
256    *
257    * <p>
258    * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types.
259    *
260    * <p>
261    * The array can be arbitrarily long to indicate arbitrarily complex data structures.
262    *
263    * <ul class='notes'>
264    *    <li>
265    *       Use the {@link #read(Object, Class)} method instead if you don't need a parameterized map/collection.
266    * </ul>
267    *
268    * @param <T> The class type of the object to create.
269    * @param input
270    *    The input.
271    *    <br>Character-based parsers can handle the following input class types:
272    *    <ul>
273    *       <li><jk>null</jk>
274    *       <li>{@link Reader}
275    *       <li>{@link CharSequence}
276    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
277    *          {@link ReaderParser#RPARSER_streamCharset} property value).
278    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
279    *          {@link ReaderParser#RPARSER_streamCharset} property value).
280    *       <li>{@link File} containing system encoded text (or charset defined by
281    *          {@link ReaderParser#RPARSER_fileCharset} property value).
282    *    </ul>
283    *    <br>Stream-based parsers can handle the following input class types:
284    *    <ul>
285    *       <li><jk>null</jk>
286    *       <li>{@link InputStream}
287    *       <li><code><jk>byte</jk>[]</code>
288    *       <li>{@link File}
289    *       <li>{@link CharSequence} containing encoded bytes according to the {@link InputStreamParser#ISPARSER_binaryFormat} setting.
290    *    </ul>
291    * @param type
292    *    The object type to create.
293    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
294    * @param args
295    *    The type arguments of the class if it's a collection or map.
296    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
297    *    <br>Ignored if the main type is not a map or collection.
298    * @return The parsed object.
299    * @throws ParseException Malformed input encountered.
300    * @throws IOException Thrown by underlying stream.
301    * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
302    */
303   public final <T> T read(Object input, Type type, Type...args) throws ParseException, IOException {
304      return p.createSession().parse(input, type, args);
305   }
306
307   /**
308    * Same as {@link #read(Object,Type,Type...)} but reads from a string and thus doesn't throw an <c>IOException</c>.
309    *
310    * @param <T> The class type of the object to create.
311    * @param input
312    *    The input.
313    *    <br>Character-based parsers can handle the following input class types:
314    *    <ul>
315    *       <li><jk>null</jk>
316    *       <li>{@link Reader}
317    *       <li>{@link CharSequence}
318    *       <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by
319    *          {@link ReaderParser#RPARSER_streamCharset} property value).
320    *       <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by
321    *          {@link ReaderParser#RPARSER_streamCharset} property value).
322    *       <li>{@link File} containing system encoded text (or charset defined by
323    *          {@link ReaderParser#RPARSER_fileCharset} property value).
324    *    </ul>
325    *    <br>Stream-based parsers can handle the following input class types:
326    *    <ul>
327    *       <li><jk>null</jk>
328    *       <li>{@link InputStream}
329    *       <li><code><jk>byte</jk>[]</code>
330    *       <li>{@link File}
331    *       <li>{@link CharSequence} containing encoded bytes according to the {@link InputStreamParser#ISPARSER_binaryFormat} setting.
332    *    </ul>
333    * @param type
334    *    The object type to create.
335    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
336    * @param args
337    *    The type arguments of the class if it's a collection or map.
338    *    <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType}
339    *    <br>Ignored if the main type is not a map or collection.
340    * @return The parsed object.
341    * @throws ParseException Malformed input encountered.
342    * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections.
343    */
344   public final <T> T read(String input, Type type, Type...args) throws ParseException {
345      return p.createSession().parse(input, type, args);
346   }
347
348   /**
349    * Same as {@link #read(Object, Type, Type...)} except optimized for a non-parameterized class.
350    *
351    * <p>
352    * This is the preferred parse method for simple types since you don't need to cast the results.
353    *
354    * <h5 class='section'>Examples:</h5>
355    * <p class='bcode w800'>
356    *    Marshall m = Json.<jsf>DEFAULT</jsf>;
357    *
358    *    <jc>// Parse into a string.</jc>
359    *    String s = m.read(json, String.<jk>class</jk>);
360    *
361    *    <jc>// Parse into a bean.</jc>
362    *    MyBean b = m.read(json, MyBean.<jk>class</jk>);
363    *
364    *    <jc>// Parse into a bean array.</jc>
365    *    MyBean[] ba = m.read(json, MyBean[].<jk>class</jk>);
366    *
367    *    <jc>// Parse into a linked-list of objects.</jc>
368    *    List l = m.read(json, LinkedList.<jk>class</jk>);
369    *
370    *    <jc>// Parse into a map of object keys/values.</jc>
371    *    Map m = m.read(json, TreeMap.<jk>class</jk>);
372    * </p>
373    *
374    * @param <T> The class type of the object being created.
375    * @param input
376    *    The input.
377    *    See {@link #read(Object, Type, Type...)} for details.
378    * @param type The object type to create.
379    * @return The parsed object.
380    * @throws ParseException Malformed input encountered.
381    * @throws IOException Thrown by underlying stream.
382    */
383   public final <T> T read(Object input, Class<T> type) throws ParseException, IOException {
384      return p.createSession().parse(input, type);
385   }
386
387   /**
388    * Same as {@link #read(Object,Class)} but reads from a string and thus doesn't throw an <c>IOException</c>.
389    *
390    * <p>
391    * This is the preferred parse method for simple types since you don't need to cast the results.
392    *
393    * <h5 class='section'>Examples:</h5>
394    * <p class='bcode w800'>
395    *    Marshall m = Json.<jsf>DEFAULT</jsf>;
396    *
397    *    <jc>// Parse into a string.</jc>
398    *    String s = m.read(json, String.<jk>class</jk>);
399    *
400    *    <jc>// Parse into a bean.</jc>
401    *    MyBean b = m.read(json, MyBean.<jk>class</jk>);
402    *
403    *    <jc>// Parse into a bean array.</jc>
404    *    MyBean[] ba = m.read(json, MyBean[].<jk>class</jk>);
405    *
406    *    <jc>// Parse into a linked-list of objects.</jc>
407    *    List l = m.read(json, LinkedList.<jk>class</jk>);
408    *
409    *    <jc>// Parse into a map of object keys/values.</jc>
410    *    Map m = m.read(json, TreeMap.<jk>class</jk>);
411    * </p>
412    *
413    * @param <T> The class type of the object being created.
414    * @param input
415    *    The input.
416    *    See {@link #read(Object, Type, Type...)} for details.
417    * @param type The object type to create.
418    * @return The parsed object.
419    * @throws ParseException Malformed input encountered.
420    */
421   public final <T> T read(String input, Class<T> type) throws ParseException {
422      return p.createSession().parse(input, type);
423   }
424}