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.jcs.*; 020import org.apache.juneau.marshall.json.*; 021import java.io.*; 022import java.lang.reflect.*; 023import org.apache.juneau.marshall.parser.*; 024import org.apache.juneau.marshall.serializer.*; 025import org.apache.juneau.marshall.stream.*; 026 027/** 028 * A pairing of a {@link JcsSerializer} and {@link JsonParser} into a single class with 029 * convenience to/of methods. 030 * 031 * <p> 032 * Produces canonical JSON per <a class="doclink" href="https://www.rfc-editor.org/rfc/rfc8785">RFC 8785</a>. 033 * Parsing uses the standard {@link JsonParser} since JCS output is valid JSON. 034 * </p> 035 * 036 * <h5 class='figure'>Examples:</h5> 037 * <p class='bjava'> 038 * <jc>// Using static convenience methods.</jc> 039 * String <jv>s</jv> = Jcs.<jsm>of</jsm>(<jv>myBean</jv>); 040 * MyBean <jv>b</jv> = Jcs.<jsm>to</jsm>(<jv>s</jv>, MyBean.<jk>class</jk>); 041 * </p> 042 * <p class='bjava'> 043 * <jc>// Using instance.</jc> 044 * Jcs <jv>jcs</jv> = <jk>new</jk> Jcs(); 045 * String <jv>s</jv> = <jv>jcs</jv>.write(<jv>myBean</jv>); 046 * MyBean <jv>b</jv> = <jv>jcs</jv>.read(<jv>s</jv>, MyBean.<jk>class</jk>); 047 * </p> 048 * 049 * <h5 class='figure'>Example output (bean with name/age):</h5> 050 * <p class='bjson'> 051 * {<jok>"age"</jok>:<jov>30</jov>,<jok>"name"</jok>:<jov>"Alice"</jov>} 052 * </p> 053 * 054 * <h5 class='section'>Notes:</h5><ul> 055 * <li class='note'> 056 * {@link java.math.BigDecimal} and {@link java.math.BigInteger} values beyond IEEE 754 double 057 * precision range will lose precision or throw during serialization. 058 * <li class='note'> 059 * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, and {@link Double#NEGATIVE_INFINITY} 060 * are not permitted and will throw during serialization. 061 * </ul> 062 * 063 * <p class='bjava'> 064 * <jc>// Using static shortcuts.</jc> 065 * MyPojo <jv>myPojo</jv> = Jcs.<jsm>to</jsm>(<jv>string</jv>, MyPojo.<jk>class</jk>); 066 * String <jv>string</jv> = Jcs.<jsm>of</jsm>(<jv>myPojo</jv>); 067 * </p> 068 * 069 * <h5 class='section'>See Also:</h5><ul> 070 * <li class='link'><a class="doclink" href="https://www.rfc-editor.org/rfc/rfc8785">RFC 8785 — JSON Canonicalization Scheme</a> 071 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Jcs">JCS</a> 072 * <li class='jc'>{@link JcsSerializer} 073 * <li class='jc'>{@link JsonParser} 074 * </ul> 075 */ 076@SuppressWarnings({ 077 "resource" // Cursor shortcut methods return Closeables owned by the caller; Eclipse JDT @Owning warning is by design. 078}) 079public class Jcs extends CharMarshaller { 080 081 /** Default reusable instance. */ 082 public static final Jcs DEFAULT = new Jcs(); 083 084 /** 085 * Serializes a POJO to a <c>String</c> using the {@link #DEFAULT} marshaller. 086 * 087 * <p> 088 * A shortcut for calling <c><jsf>DEFAULT</jsf>.write(<jv>object</jv>)</c>. 089 * 090 * @param object The object to serialize. 091 * @return The serialized object. 092 * @throws SerializeException If a problem occurred trying to convert the output. 093 */ 094 public static String of(Object object) throws SerializeException { 095 return DEFAULT.write(object); 096 } 097 098 /** 099 * Parses an input into the specified object type using the {@link #DEFAULT} marshaller. 100 * 101 * <p> 102 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>)</c>. 103 * 104 * @param <T> The class type of the object being created. 105 * @param input The input. 106 * @param type The object type to create. 107 * @return The parsed object. 108 * @throws ParseException Malformed input encountered. 109 */ 110 public static <T> T to(String input, Class<T> type) throws ParseException { 111 return DEFAULT.read(input, type); 112 } 113 114 /** 115 * Parses an input into the specified parameterized object type using the {@link #DEFAULT} marshaller. 116 * 117 * <p> 118 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>, <jv>args</jv>)</c>. 119 * 120 * @param <T> The class type of the object to create. 121 * @param input The input. 122 * @param type The object type to create. 123 * @param args The type arguments of the class if it's a collection or map. 124 * @return The parsed object. 125 * @throws ParseException Malformed input encountered. 126 */ 127 public static <T> T to(String input, Type type, Type... args) throws ParseException { 128 return DEFAULT.read(input, type, args); 129 } 130 131 /** 132 * Parses the contents of a {@link Reader} into the specified object type using the {@link #DEFAULT} marshaller. 133 * 134 * <p> 135 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>)</c> that catches any 136 * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link ParseException}, so the 137 * caller is not burdened with a checked exception. 138 * 139 * @param <T> The class type of the object being created. 140 * @param input The input reader. 141 * @param type The object type to create. 142 * @return The parsed object. 143 * @throws ParseException Malformed input encountered or an I/O error occurred on the underlying stream. 144 */ 145 public static <T> T to(Reader input, Class<T> type) throws ParseException { 146 try { 147 return DEFAULT.read(input, type); 148 } catch (IOException e) { 149 throw new ParseException(e); 150 } 151 } 152 153 /** 154 * Parses the contents of a {@link Reader} into the specified parameterized object type using the {@link #DEFAULT} marshaller. 155 * 156 * <p> 157 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>, <jv>args</jv>)</c> that catches any 158 * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link ParseException}, so the 159 * caller is not burdened with a checked exception. 160 * 161 * @param <T> The class type of the object to create. 162 * @param input The input reader. 163 * @param type The object type to create. 164 * @param args The type arguments of the class if it's a collection or map. 165 * @return The parsed object. 166 * @throws ParseException Malformed input encountered or an I/O error occurred on the underlying stream. 167 */ 168 public static <T> T to(Reader input, Type type, Type... args) throws ParseException { 169 try { 170 return DEFAULT.read(input, type, args); 171 } catch (IOException e) { 172 throw new ParseException(e); 173 } 174 } 175 176 /** 177 * Serializes a POJO to the specified {@link Writer} using the {@link #DEFAULT} marshaller. 178 * 179 * <p> 180 * A shortcut for calling <c><jsf>DEFAULT</jsf>.write(<jv>object</jv>, <jv>output</jv>)</c> that catches any 181 * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link SerializeException}, so the 182 * caller is not burdened with a checked exception. 183 * 184 * @param object The object to serialize. 185 * @param output The writer to serialize to. 186 * @throws SerializeException If a problem occurred trying to convert the output or an I/O error occurred on the underlying stream. 187 */ 188 public static void of(Object object, Writer output) throws SerializeException { 189 try { 190 DEFAULT.write(object, output); 191 } catch (IOException e) { 192 throw new SerializeException(e); 193 } 194 } 195 196 /** 197 * Opens a low-level {@link TokenReader} cursor over the specified input using the {@link #DEFAULT} marshaller. 198 * 199 * <p> 200 * A shortcut for calling <c><jsf>DEFAULT</jsf>.readTokens(<jv>input</jv>)</c>. 201 * 202 * @param input The input. 203 * @return A new {@link TokenReader}. 204 * @throws IOException If a problem occurred opening the underlying input. 205 */ 206 public static TokenReader toTokens(Object input) throws IOException { 207 return DEFAULT.readTokens(input); 208 } 209 210 /** 211 * Opens a low-level {@link TokenWriter} generator over the specified output using the {@link #DEFAULT} marshaller. 212 * 213 * <p> 214 * A shortcut for calling <c><jsf>DEFAULT</jsf>.writeTokens(<jv>output</jv>)</c>. 215 * 216 * @param output The output. 217 * @return A new {@link TokenWriter}. 218 * @throws IOException If a problem occurred opening the underlying output. 219 */ 220 public static TokenWriter ofTokens(Object output) throws IOException { 221 return DEFAULT.writeTokens(output); 222 } 223 224 /** 225 * Opens a low-level {@link RecordReader} cursor over the specified input using the {@link #DEFAULT} marshaller. 226 * 227 * <p> 228 * A shortcut for calling <c><jsf>DEFAULT</jsf>.readRecords(<jv>input</jv>)</c>. 229 * 230 * @param input The input. 231 * @return A new {@link RecordReader}. 232 * @throws IOException If a problem occurred opening the underlying input. 233 */ 234 public static RecordReader toRecords(Object input) throws IOException { 235 return DEFAULT.readRecords(input); 236 } 237 238 /** 239 * Opens a low-level {@link RecordWriter} cursor over the specified output using the {@link #DEFAULT} marshaller. 240 * 241 * <p> 242 * A shortcut for calling <c><jsf>DEFAULT</jsf>.writeRecords(<jv>output</jv>)</c>. 243 * 244 * @param output The output. 245 * @return A new {@link RecordWriter}. 246 * @throws IOException If a problem occurred opening the underlying output. 247 */ 248 public static RecordWriter ofRecords(Object output) throws IOException { 249 return DEFAULT.writeRecords(output); 250 } 251 252 /** 253 * Opens a {@link RecordReader} that yields each element of a top-level wire array using the {@link #DEFAULT} marshaller. 254 * 255 * <p> 256 * A shortcut for calling <c><jsf>DEFAULT</jsf>.readArrayRecords(<jv>input</jv>)</c>. 257 * 258 * @param input The input. 259 * @return A new {@link RecordReader}. 260 * @throws IOException If a problem occurred opening the underlying input. 261 */ 262 public static RecordReader toArrayRecords(Object input) throws IOException { 263 return DEFAULT.readArrayRecords(input); 264 } 265 266 /** 267 * Opens a {@link RecordWriter} that wraps each written value as one element of a top-level wire array using the {@link #DEFAULT} marshaller. 268 * 269 * <p> 270 * A shortcut for calling <c><jsf>DEFAULT</jsf>.writeArrayRecords(<jv>output</jv>)</c>. 271 * 272 * @param output The output. 273 * @return A new {@link RecordWriter}. 274 * @throws IOException If a problem occurred opening the underlying output. 275 */ 276 public static RecordWriter ofArrayRecords(Object output) throws IOException { 277 return DEFAULT.writeArrayRecords(output); 278 } 279 280 /** 281 * Constructor. 282 * 283 * <p> 284 * Uses {@link JcsSerializer#DEFAULT} and {@link JsonParser#DEFAULT}. 285 */ 286 public Jcs() { 287 this(JcsSerializer.DEFAULT, JsonParser.DEFAULT); 288 } 289 290 /** 291 * Constructor. 292 * 293 * @param s The serializer to use for serializing output. 294 * @param p The parser to use for parsing input. 295 */ 296 public Jcs(JcsSerializer s, JsonParser p) { 297 super(s, p); 298 } 299}