001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.serializer;
014
015import org.apache.juneau.*;
016import org.apache.juneau.utils.*;
017
018/**
019 * Subclass of {@link Serializer} for character-based serializers.
020 */
021public abstract class WriterSerializer extends Serializer {
022
023   //-------------------------------------------------------------------------------------------------------------------
024   // Configurable properties
025   //-------------------------------------------------------------------------------------------------------------------
026
027   private static final String PREFIX = "WriterSerializer.";
028
029   /**
030    * Configuration property:  Maximum indentation.
031    *
032    * <h5 class='section'>Property:</h5>
033    * <ul>
034    *    <li><b>Name:</b>  <js>"WriterSerializer.maxIndent.i"</js>
035    *    <li><b>Data type:</b>  <code>Integer</code>
036    *    <li><b>Default:</b>  <code>100</code>
037    *    <li><b>Session property:</b>  <jk>false</jk>
038    *    <li><b>Methods:</b>
039    *       <ul>
040    *          <li class='jm'>{@link WriterSerializerBuilder#maxIndent(int)}
041    *       </ul>
042    * </ul>
043    *
044    * <h5 class='section'>Description:</h5>
045    * <p>
046    * Specifies the maximum indentation level in the serialized document.
047    *
048    * <p>
049    * This setting does not apply to the RDF serializers.
050    *
051    * <h5 class='section'>Example:</h5>
052    * <p class='bcode w800'>
053    *    <jc>// Create a serializer that indents a maximum of 20 tabs.</jc>
054    *    WriterSerializer s = JsonSerializer
055    *       .<jsm>create</jsm>()
056    *       .maxIndent(20)
057    *       .build();
058    *
059    *    <jc>// Same, but use property.</jc>
060    *    WriterSerializer s = JsonSerializer
061    *       .<jsm>create</jsm>()
062    *       .set(<jsf>SERIALIZER_maxIndent</jsf>, 20)
063    *       .build();
064    * </p>
065    */
066   public static final String WSERIALIZER_maxIndent = PREFIX + "maxIndent.i";
067
068   /**
069    * Configuration property:  Quote character.
070    *
071    * <h5 class='section'>Property:</h5>
072    * <ul>
073    *    <li><b>Name:</b>  <js>"WriterSerializer.quoteChar.s"</js>
074    *    <li><b>Data type:</b>  <code>String</code>
075    *    <li><b>Default:</b>  <js>"\""</js>
076    *    <li><b>Session property:</b>  <jk>false</jk>
077    *    <li><b>Methods:</b>
078    *       <ul>
079    *          <li class='jm'>{@link WriterSerializerBuilder#quoteChar(char)}
080    *          <li class='jm'>{@link WriterSerializerBuilder#sq()}
081    *       </ul>
082    * </ul>
083    *
084    * <h5 class='section'>Description:</h5>
085    * <p>
086    * This is the character used for quoting attributes and values.
087    *
088    * <p>
089    * This setting does not apply to the RDF serializers.
090    *
091    * <h5 class='section'>Example:</h5>
092    * <p class='bcode w800'>
093    *    <jc>// Create a serializer that uses single quotes.</jc>
094    *    WriterSerializer s = JsonSerializer
095    *       .<jsm>create</jsm>()
096    *       .sq()
097    *       .build();
098    *
099    *    <jc>// Same, but use property.</jc>
100    *    WriterSerializer s = JsonSerializer
101    *       .<jsm>create</jsm>()
102    *       .set(<jsf>WSERIALIZER_quoteChar</jsf>, <js>'\''</js>)
103    *       .build();
104    * </p>
105    */
106   public static final String WSERIALIZER_quoteChar = PREFIX + "quoteChar.s";
107
108   static final WriterSerializer DEFAULT = new WriterSerializer(PropertyStore.create().build(), "", "") {
109      @Override
110      public WriterSerializerSession createSession(SerializerSessionArgs args) {
111         throw new NoSuchMethodError();
112      }
113   };
114
115   //-------------------------------------------------------------------------------------------------------------------
116   // Instance
117   //-------------------------------------------------------------------------------------------------------------------
118
119   private final int maxIndent;
120   private final char quoteChar;
121
122   /**
123    * Constructor.
124    *
125    * @param ps
126    *    The property store containing all the settings for this object.
127    * @param produces
128    *    The media type that this serializer produces.
129    * @param accept
130    *    The accept media types that the serializer can handle.
131    *    <p>
132    *    Can contain meta-characters per the <code>media-type</code> specification of {@doc RFC2616.section14.1}
133    *    <p>
134    *    If empty, then assumes the only media type supported is <code>produces</code>.
135    *    <p>
136    *    For example, if this serializer produces <js>"application/json"</js> but should handle media types of
137    *    <js>"application/json"</js> and <js>"text/json"</js>, then the arguments should be:
138    *    <p class='bcode w800'>
139    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"application/json,text/json"</js>);
140    *    </p>
141    *    <br>...or...
142    *    <p class='bcode w800'>
143    *    <jk>super</jk>(ps, <js>"application/json"</js>, <js>"*&#8203;/json"</js>);
144    *    </p>
145    * <p>
146    * The accept value can also contain q-values.
147    */
148   protected WriterSerializer(PropertyStore ps, String produces, String accept) {
149      super(ps, produces, accept);
150
151      maxIndent = getIntegerProperty(WSERIALIZER_maxIndent, 100);
152      quoteChar = getStringProperty(WSERIALIZER_quoteChar, "\"").charAt(0);
153   }
154
155
156   //-----------------------------------------------------------------------------------------------------------------
157   // Abstract methods
158   //-----------------------------------------------------------------------------------------------------------------
159
160   @Override /* SerializerSession */
161   public abstract WriterSerializerSession createSession(SerializerSessionArgs args);
162
163
164   //-----------------------------------------------------------------------------------------------------------------
165   // Other methods
166   //-----------------------------------------------------------------------------------------------------------------
167
168   @Override /* Serializer */
169   public final boolean isWriterSerializer() {
170      return true;
171   }
172
173   /**
174    * Convenience method for serializing an object to a <code>String</code>.
175    *
176    * @param o The object to serialize.
177    * @return The output serialized to a string.
178    * @throws SerializeException If a problem occurred trying to convert the output.
179    */
180   @Override /* Serializer */
181   public final String serialize(Object o) throws SerializeException {
182      return createSession(createDefaultSessionArgs()).serialize(o);
183   }
184
185   /**
186    * Identical to {@link #serialize(Object)} except throws a {@link RuntimeException} instead of a {@link SerializeException}.
187    *
188    * <p>
189    * This is typically good enough for debugging purposes.
190    *
191    * @param o The object to serialize.
192    * @return The serialized object.
193    */
194   public final String toString(Object o) {
195      try {
196         return serialize(o);
197      } catch (Exception e) {
198         throw new RuntimeException(e);
199      }
200   }
201
202   /**
203    * Wraps the specified object inside a {@link StringObject}.
204    *
205    * @param o The object to wrap.
206    * @return The wrapped object.
207    */
208   public final StringObject toStringObject(Object o) {
209      return new StringObject(this, o);
210   }
211
212   /**
213    * Convenience method for serializing an object and sending it to STDOUT.
214    *
215    * @param o The object to serialize.
216    * @return This object (for method chaining).
217    */
218   public final WriterSerializer println(Object o) {
219      System.out.println(toString(o));  // NOT DEBUG
220      return this;
221   }
222
223   //-----------------------------------------------------------------------------------------------------------------
224   // Properties
225   //-----------------------------------------------------------------------------------------------------------------
226
227   /**
228    * Configuration property:  Maximum indentation.
229    *
230    * @see #WSERIALIZER_maxIndent
231    * @return
232    *    The maximum indentation level in the serialized document.
233    */
234   protected final int getMaxIndent() {
235      return maxIndent;
236   }
237
238   /**
239    * Configuration property:  Quote character.
240    *
241    * @see #WSERIALIZER_quoteChar
242    * @return
243    *    The character used for quoting attributes and values.
244    */
245   protected final char getQuoteChar() {
246      return quoteChar;
247   }
248
249   @Override /* Context */
250   public ObjectMap asMap() {
251      return super.asMap()
252         .append("WriterSerializer", new ObjectMap()
253            .append("maxIndent", maxIndent)
254            .append("quoteChar", quoteChar)
255         );
256   }
257}