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.marshaller; 018 019import java.io.*; 020import java.lang.reflect.*; 021import java.nio.charset.*; 022 023import org.apache.juneau.*; 024import org.apache.juneau.parser.*; 025import org.apache.juneau.serializer.*; 026 027/** 028 * Top-level class for a pairing of a {@link Serializer} and {@link Parser} into a single class with convenience read/write methods. 029 * 030 * <p> 031 * The general idea is to combine a single serializer and parser inside a simplified API for reading and writing POJOs. 032 * 033 * <h5 class='figure'>Examples:</h5> 034 * <p class='bjava'> 035 * <jc>// Using instance.</jc> 036 * Marshaller <jv>json</jv> = <jk>new</jk> Json(); 037 * MyPojo <jv>myPojo</jv> = <jv>json</jv>.read(<jv>string</jv>, MyPojo.<jk>class</jk>); 038 * String <jv>string</jv> = <jv>json</jv>.write(<jv>myPojo</jv>); 039 * </p> 040 * <p class='bjava'> 041 * <jc>// Using DEFAULT instance.</jc> 042 * MyPojo <jv>myPojo</jv> = Json.<jsf>DEFAULT</jsf>.read(<jv>string</jv>, MyPojo.<jk>class</jk>); 043 * String <jv>string</jv> = Json.<jsf>DEFAULT</jsf>.write(<jv>myPojo</jv>); 044 * </p> 045 * 046 * <h5 class='section'>See Also:</h5><ul> 047 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Marshallers">Marshallers</a> 048 * </ul> 049 */ 050public abstract class Marshaller { 051 052 //----------------------------------------------------------------------------------------------------------------- 053 // Instance 054 //----------------------------------------------------------------------------------------------------------------- 055 056 private final Serializer s; 057 private final Parser p; 058 059 /** 060 * Constructor. 061 * 062 * @param s 063 * The serializer to use for serializing output. 064 * <br>Must not be <jk>null</jk>. 065 * @param p 066 * The parser to use for parsing input. 067 * <br>Must not be <jk>null</jk>. 068 */ 069 protected Marshaller(Serializer s, Parser p) { 070 this.s = s; 071 this.p = p; 072 } 073 074 /** 075 * Returns the serializer associated with this marshaller. 076 * 077 * @return The serializer associated with this marshaller. 078 */ 079 public Serializer getSerializer() { 080 return s; 081 } 082 083 /** 084 * Returns the parser associated with this marshaller. 085 * 086 * @return The parser associated with this marshaller. 087 */ 088 public Parser getParser() { 089 return p; 090 } 091 092 /** 093 * Serializes a POJO to the specified output stream or writer. 094 * 095 * <p> 096 * Equivalent to calling <c>serializer.createSession().serialize(o, output);</c> 097 * 098 * @param object The object to serialize. 099 * @param output 100 * The output object. 101 * <br>Character-based serializers can handle the following output class types: 102 * <ul> 103 * <li>{@link Writer} 104 * <li>{@link OutputStream} - Output will be written as UTF-8 encoded stream. 105 * <li>{@link File} - Output will be written as system-default encoded stream. 106 * <li>{@link StringBuilder} - Output will be written to the specified string builder. 107 * </ul> 108 * <br>Stream-based serializers can handle the following output class types: 109 * <ul> 110 * <li>{@link OutputStream} 111 * <li>{@link File} 112 * </ul> 113 * @throws SerializeException If a problem occurred trying to convert the output. 114 * @throws IOException Thrown by underlying stream. 115 */ 116 public final void write(Object object, Object output) throws SerializeException, IOException { 117 s.serialize(object, output); 118 } 119 120 /** 121 * Parses input into the specified object type. 122 * 123 * <p> 124 * The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps). 125 * 126 * <h5 class='section'>Examples:</h5> 127 * <p class='bjava'> 128 * Marshaller <jv>marshaller</jv> = Json.<jsf>DEFAULT</jsf>; 129 * 130 * <jc>// Parse into a linked-list of strings.</jc> 131 * List <jv>list1</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 132 * 133 * <jc>// Parse into a linked-list of beans.</jc> 134 * List <jv>list2</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>, MyBean.<jk>class</jk>); 135 * 136 * <jc>// Parse into a linked-list of linked-lists of strings.</jc> 137 * List <jv>list3</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>, LinkedList.<jk>class</jk>, String.<jk>class</jk>); 138 * 139 * <jc>// Parse into a map of string keys/values.</jc> 140 * Map <jv>map1</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, TreeMap.<jk>class</jk>, String.<jk>class</jk>, String.<jk>class</jk>); 141 * 142 * <jc>// Parse into a map containing string keys and values of lists containing beans.</jc> 143 * 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>); 144 * </p> 145 * 146 * <p> 147 * <c>Collection</c> classes are assumed to be followed by zero or one objects indicating the element type. 148 * 149 * <p> 150 * <c>Map</c> classes are assumed to be followed by zero or two meta objects indicating the key and value types. 151 * 152 * <p> 153 * The array can be arbitrarily long to indicate arbitrarily complex data structures. 154 * 155 * <h5 class='section'>Notes:</h5><ul> 156 * <li class='note'> 157 * Use the {@link #read(Object, Class)} method instead if you don't need a parameterized map/collection. 158 * </ul> 159 * 160 * @param <T> The class type of the object to create. 161 * @param input 162 * The input. 163 * <br>Character-based parsers can handle the following input class types: 164 * <ul> 165 * <li><jk>null</jk> 166 * <li>{@link Reader} 167 * <li>{@link CharSequence} 168 * <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by 169 * {@link org.apache.juneau.parser.ReaderParser.Builder#streamCharset(Charset)} property value). 170 * <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by 171 * {@link org.apache.juneau.parser.ReaderParser.Builder#streamCharset(Charset)} property value). 172 * <li>{@link File} containing system encoded text (or charset defined by 173 * {@link org.apache.juneau.parser.ReaderParser.Builder#fileCharset(Charset)} property value). 174 * </ul> 175 * <br>Stream-based parsers can handle the following input class types: 176 * <ul> 177 * <li><jk>null</jk> 178 * <li>{@link InputStream} 179 * <li><code><jk>byte</jk>[]</code> 180 * <li>{@link File} 181 * <li>{@link CharSequence} containing encoded bytes according to the {@link org.apache.juneau.parser.InputStreamParser.Builder#binaryFormat(BinaryFormat)} setting. 182 * </ul> 183 * @param type 184 * The object type to create. 185 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 186 * @param args 187 * The type arguments of the class if it's a collection or map. 188 * <br>Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, {@link GenericArrayType} 189 * <br>Ignored if the main type is not a map or collection. 190 * @return The parsed object. 191 * @throws ParseException Malformed input encountered. 192 * @throws IOException Thrown by underlying stream. 193 * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections. 194 */ 195 public final <T> T read(Object input, Type type, Type...args) throws ParseException, IOException { 196 return p.parse(input, type, args); 197 } 198 199 /** 200 * Same as {@link #read(Object, Type, Type...)} except optimized for a non-parameterized class. 201 * 202 * <p> 203 * This is the preferred parse method for simple types since you don't need to cast the results. 204 * 205 * <h5 class='section'>Examples:</h5> 206 * <p class='bjava'> 207 * Marshaller <jv>marshaller</jv> = Json.<jsf>DEFAULT</jsf>; 208 * 209 * <jc>// Parse into a string.</jc> 210 * String <jv>string</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, String.<jk>class</jk>); 211 * 212 * <jc>// Parse into a bean.</jc> 213 * MyBean <jv>bean</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, MyBean.<jk>class</jk>); 214 * 215 * <jc>// Parse into a bean array.</jc> 216 * MyBean[] <jv>beanArray</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, MyBean[].<jk>class</jk>); 217 * 218 * <jc>// Parse into a linked-list of objects.</jc> 219 * List <jv>list</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, LinkedList.<jk>class</jk>); 220 * 221 * <jc>// Parse into a map of object keys/values.</jc> 222 * Map <jv>map</jv> = <jv>marshaller</jv> .read(<jv>json</jv>, TreeMap.<jk>class</jk>); 223 * </p> 224 * 225 * @param <T> The class type of the object being created. 226 * @param input 227 * The input. 228 * <br>Character-based parsers can handle the following input class types: 229 * <ul> 230 * <li><jk>null</jk> 231 * <li>{@link Reader} 232 * <li>{@link CharSequence} 233 * <li>{@link InputStream} containing UTF-8 encoded text (or charset defined by 234 * {@link org.apache.juneau.parser.ReaderParser.Builder#streamCharset(Charset)} property value). 235 * <li><code><jk>byte</jk>[]</code> containing UTF-8 encoded text (or charset defined by 236 * {@link org.apache.juneau.parser.ReaderParser.Builder#streamCharset(Charset)} property value). 237 * <li>{@link File} containing system encoded text (or charset defined by 238 * {@link org.apache.juneau.parser.ReaderParser.Builder#fileCharset(Charset)} property value). 239 * </ul> 240 * <br>Stream-based parsers can handle the following input class types: 241 * <ul> 242 * <li><jk>null</jk> 243 * <li>{@link InputStream} 244 * <li><code><jk>byte</jk>[]</code> 245 * <li>{@link File} 246 * <li>{@link CharSequence} containing encoded bytes according to the {@link org.apache.juneau.parser.InputStreamParser.Builder#binaryFormat(BinaryFormat)} setting. 247 * </ul> 248 * @param type The object type to create. 249 * @return The parsed object. 250 * @throws ParseException Malformed input encountered. 251 * @throws IOException Thrown by underlying stream. 252 */ 253 public final <T> T read(Object input, Class<T> type) throws ParseException, IOException { 254 return p.parse(input, type); 255 } 256}