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.prototext.*; 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 PrototextSerializer} and {@link PrototextParser} 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 * Prototext <jv>proto</jv> = <jk>new</jk> Prototext(); 036 * MyPojo <jv>myPojo</jv> = <jv>proto</jv>.read(<jv>string</jv>, MyPojo.<jk>class</jk>); 037 * String <jv>string</jv> = <jv>proto</jv>.write(<jv>myPojo</jv>); 038 * </p> 039 * <p class='bjava'> 040 * <jc>// Using DEFAULT instance.</jc> 041 * MyPojo <jv>myPojo</jv> = Prototext.<jsf>DEFAULT</jsf>.read(<jv>string</jv>, MyPojo.<jk>class</jk>); 042 * String <jv>string</jv> = Prototext.<jsf>DEFAULT</jsf>.write(<jv>myPojo</jv>); 043 * </p> 044 * 045 * <h5 class='figure'>Example output (Map of name/age):</h5> 046 * <p class='bcode'> 047 * name: "Alice" 048 * age: 30 049 * </p> 050 * 051 * <h5 class='figure'>Complex (nested object + array):</h5> 052 * <p class='bcode'> 053 * name: "Alice" 054 * age: 30 055 * address { 056 * street: "123 Main St" 057 * city: "Boston" 058 * state: "MA" 059 * } 060 * tags: ["a", "b", "c"] 061 * </p> 062 * 063 * <p class='bjava'> 064 * <jc>// Using static shortcuts.</jc> 065 * MyPojo <jv>myPojo</jv> = Prototext.<jsm>to</jsm>(<jv>string</jv>, MyPojo.<jk>class</jk>); 066 * String <jv>string</jv> = Prototext.<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://juneau.apache.org/docs/topics/Marshallers">Marshallers</a> 071 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/Prototext">Protobuf Text Format Basics</a> 072 * </ul> 073 */ 074@SuppressWarnings({ 075 "resource" // Cursor shortcut methods return Closeables owned by the caller; Eclipse JDT @Owning warning is by design. 076}) 077public class Prototext extends CharMarshaller { 078 079 /** Default marshaller instance. */ 080 public static final Prototext DEFAULT = new Prototext(); 081 082 /** 083 * Serializes a POJO to a <c>String</c> using the {@link #DEFAULT} marshaller. 084 * 085 * <p> 086 * A shortcut for calling <c><jsf>DEFAULT</jsf>.write(<jv>object</jv>)</c>. 087 * 088 * @param object The object to serialize. 089 * @return The serialized object. 090 * @throws SerializeException If a problem occurred trying to convert the output. 091 */ 092 public static String of(Object object) throws SerializeException { 093 return DEFAULT.write(object); 094 } 095 096 /** 097 * Parses an input into the specified object type using the {@link #DEFAULT} marshaller. 098 * 099 * <p> 100 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>)</c>. 101 * 102 * @param <T> The class type of the object being created. 103 * @param input The input. 104 * @param type The object type to create. 105 * @return The parsed object. 106 * @throws ParseException Malformed input encountered. 107 */ 108 public static <T> T to(String input, Class<T> type) throws ParseException { 109 return DEFAULT.read(input, type); 110 } 111 112 /** 113 * Parses an input into the specified parameterized object type using the {@link #DEFAULT} marshaller. 114 * 115 * <p> 116 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>, <jv>args</jv>)</c>. 117 * 118 * @param <T> The class type of the object to create. 119 * @param input The input. 120 * @param type The object type to create. 121 * @param args The type arguments of the class if it's a collection or map. 122 * @return The parsed object. 123 * @throws ParseException Malformed input encountered. 124 */ 125 public static <T> T to(String input, Type type, Type... args) throws ParseException { 126 return DEFAULT.read(input, type, args); 127 } 128 129 /** 130 * Parses the contents of a {@link Reader} into the specified object type using the {@link #DEFAULT} marshaller. 131 * 132 * <p> 133 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>)</c> that catches any 134 * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link ParseException}, so the 135 * caller is not burdened with a checked exception. 136 * 137 * @param <T> The class type of the object being created. 138 * @param input The input reader. 139 * @param type The object type to create. 140 * @return The parsed object. 141 * @throws ParseException Malformed input encountered or an I/O error occurred on the underlying stream. 142 */ 143 public static <T> T to(Reader input, Class<T> type) throws ParseException { 144 try { 145 return DEFAULT.read(input, type); 146 } catch (IOException e) { 147 throw new ParseException(e); 148 } 149 } 150 151 /** 152 * Parses the contents of a {@link Reader} into the specified parameterized object type using the {@link #DEFAULT} marshaller. 153 * 154 * <p> 155 * A shortcut for calling <c><jsf>DEFAULT</jsf>.read(<jv>input</jv>, <jv>type</jv>, <jv>args</jv>)</c> that catches any 156 * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link ParseException}, so the 157 * caller is not burdened with a checked exception. 158 * 159 * @param <T> The class type of the object to create. 160 * @param input The input reader. 161 * @param type The object type to create. 162 * @param args The type arguments of the class if it's a collection or map. 163 * @return The parsed object. 164 * @throws ParseException Malformed input encountered or an I/O error occurred on the underlying stream. 165 */ 166 public static <T> T to(Reader input, Type type, Type... args) throws ParseException { 167 try { 168 return DEFAULT.read(input, type, args); 169 } catch (IOException e) { 170 throw new ParseException(e); 171 } 172 } 173 174 /** 175 * Serializes a POJO to the specified {@link Writer} using the {@link #DEFAULT} marshaller. 176 * 177 * <p> 178 * A shortcut for calling <c><jsf>DEFAULT</jsf>.write(<jv>object</jv>, <jv>output</jv>)</c> that catches any 179 * {@link IOException} from the underlying stream and rethrows it as an unchecked {@link SerializeException}, so the 180 * caller is not burdened with a checked exception. 181 * 182 * @param object The object to serialize. 183 * @param output The writer to serialize to. 184 * @throws SerializeException If a problem occurred trying to convert the output or an I/O error occurred on the underlying stream. 185 */ 186 public static void of(Object object, Writer output) throws SerializeException { 187 try { 188 DEFAULT.write(object, output); 189 } catch (IOException e) { 190 throw new SerializeException(e); 191 } 192 } 193 194 /** 195 * Opens a low-level {@link RecordReader} cursor over the specified input using the {@link #DEFAULT} marshaller. 196 * 197 * <p> 198 * A shortcut for calling <c><jsf>DEFAULT</jsf>.readRecords(<jv>input</jv>)</c>. 199 * 200 * @param input The input. 201 * @return A new {@link RecordReader}. 202 * @throws IOException If a problem occurred opening the underlying input. 203 */ 204 public static RecordReader toRecords(Object input) throws IOException { 205 return DEFAULT.readRecords(input); 206 } 207 208 /** 209 * Opens a low-level {@link RecordWriter} cursor over the specified output using the {@link #DEFAULT} marshaller. 210 * 211 * <p> 212 * A shortcut for calling <c><jsf>DEFAULT</jsf>.writeRecords(<jv>output</jv>)</c>. 213 * 214 * @param output The output. 215 * @return A new {@link RecordWriter}. 216 * @throws IOException If a problem occurred opening the underlying output. 217 */ 218 public static RecordWriter ofRecords(Object output) throws IOException { 219 return DEFAULT.writeRecords(output); 220 } 221 222 /** Creates using default serializer and parser. */ 223 public Prototext() { 224 this(PrototextSerializer.DEFAULT, PrototextParser.DEFAULT); 225 } 226 227 /** 228 * Creates with custom serializer and parser. 229 * 230 * @param s The serializer. 231 * @param p The parser. 232 */ 233 public Prototext(PrototextSerializer s, PrototextParser p) { 234 super(s, p); 235 } 236}