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