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