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.serializer;
018
019import static org.apache.juneau.collections.JsonMap.*;
020
021import java.io.*;
022import java.lang.reflect.*;
023import java.nio.charset.*;
024import java.util.*;
025import java.util.function.*;
026
027import org.apache.juneau.*;
028import org.apache.juneau.collections.*;
029import org.apache.juneau.httppart.*;
030import org.apache.juneau.internal.*;
031import org.apache.juneau.svl.*;
032
033/**
034 * Subclass of {@link SerializerSession} for character-based serializers.
035 *
036 * <h5 class='topic'>Description</h5>
037 *
038 * This class is typically the parent class of all character-based serializers.
039 * <br>It has 1 abstract method to implement...
040 * <ul class='spaced-list'>
041 *    <li>
042 *       {@link #doSerialize(SerializerPipe, Object)}
043 * </ul>
044 *
045 * <h5 class='section'>Notes:</h5><ul>
046 *    <li class='warn'>This class is not thread safe and is typically discarded after one use.
047 * </ul>
048 *
049 * <h5 class='section'>See Also:</h5><ul>
050 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/SerializersAndParsers">Serializers and Parsers</a>
051 * </ul>
052 */
053public class WriterSerializerSession extends SerializerSession {
054
055   //-------------------------------------------------------------------------------------------------------------------
056   // Static
057   //-------------------------------------------------------------------------------------------------------------------
058
059   /**
060    * Creates a new builder for this object.
061    *
062    * @param ctx The context creating this session.
063    * @return A new builder.
064    */
065   public static Builder create(WriterSerializer ctx) {
066      return new Builder(ctx);
067   }
068
069   //-----------------------------------------------------------------------------------------------------------------
070   // Builder
071   //-----------------------------------------------------------------------------------------------------------------
072
073   /**
074    * Builder class.
075    */
076   public static class Builder extends SerializerSession.Builder {
077
078      WriterSerializer ctx;
079      boolean useWhitespace;
080      Charset fileCharset, streamCharset;
081
082      /**
083       * Constructor
084       *
085       * @param ctx The context creating this session.
086       */
087      protected Builder(WriterSerializer ctx) {
088         super(ctx);
089         this.ctx = ctx;
090         useWhitespace = ctx.useWhitespace;
091         fileCharset = ctx.fileCharset;
092         streamCharset = ctx.streamCharset;
093      }
094
095      @Override
096      public WriterSerializerSession build() {
097         return new WriterSerializerSession(this);
098      }
099
100      /**
101       * File charset.
102       *
103       * <p>
104       * The character set to use for writing Files to the file system.
105       *
106       * <p>
107       * Used when passing in files to {@link Serializer#serialize(Object, Object)}.
108       *
109       * <p>
110       * If not specified, defaults to the JVM system default charset.
111       *
112       * @param value
113       *    The new property value.
114       *    <br>Can be <jk>null</jk>.
115       * @return This object.
116       */
117      public Builder fileCharset(Charset value) {
118         if (value != null)
119            fileCharset = value;
120         return this;
121      }
122
123      /**
124       * Output stream charset.
125       *
126       * <p>
127       * The character set to use when writing to OutputStreams.
128       *
129       * <p>
130       * Used when passing in output streams and byte arrays to {@link WriterSerializer#serialize(Object, Object)}.
131       *
132       * <p>
133       * If not specified, defaults to UTF-8.
134       *
135       * @param value
136       *    The new property value.
137       *    <br>Can be <jk>null</jk>.
138       * @return This object.
139       */
140      public Builder streamCharset(Charset value) {
141         if (value != null)
142            streamCharset = value;
143         return this;
144      }
145
146      /**
147       * Use whitespace.
148       *
149       * <p>
150       * If true, whitespace is added to the output to improve readability.
151       *
152       * @param value
153       *    The new property value.
154       *    <br>Can be <jk>null</jk>.
155       * @return This object.
156       */
157      public Builder useWhitespace(Boolean value) {
158         if (value != null)
159            useWhitespace = value;
160         return this;
161      }
162      @Override /* Overridden from Builder */
163      public <T> Builder apply(Class<T> type, Consumer<T> apply) {
164         super.apply(type, apply);
165         return this;
166      }
167
168      @Override /* Overridden from Builder */
169      public Builder debug(Boolean value) {
170         super.debug(value);
171         return this;
172      }
173
174      @Override /* Overridden from Builder */
175      public Builder properties(Map<String,Object> value) {
176         super.properties(value);
177         return this;
178      }
179
180      @Override /* Overridden from Builder */
181      public Builder property(String key, Object value) {
182         super.property(key, value);
183         return this;
184      }
185
186      @Override /* Overridden from Builder */
187      public Builder unmodifiable() {
188         super.unmodifiable();
189         return this;
190      }
191
192      @Override /* Overridden from Builder */
193      public Builder locale(Locale value) {
194         super.locale(value);
195         return this;
196      }
197
198      @Override /* Overridden from Builder */
199      public Builder localeDefault(Locale value) {
200         super.localeDefault(value);
201         return this;
202      }
203
204      @Override /* Overridden from Builder */
205      public Builder mediaType(MediaType value) {
206         super.mediaType(value);
207         return this;
208      }
209
210      @Override /* Overridden from Builder */
211      public Builder mediaTypeDefault(MediaType value) {
212         super.mediaTypeDefault(value);
213         return this;
214      }
215
216      @Override /* Overridden from Builder */
217      public Builder timeZone(TimeZone value) {
218         super.timeZone(value);
219         return this;
220      }
221
222      @Override /* Overridden from Builder */
223      public Builder timeZoneDefault(TimeZone value) {
224         super.timeZoneDefault(value);
225         return this;
226      }
227
228      @Override /* Overridden from Builder */
229      public Builder javaMethod(Method value) {
230         super.javaMethod(value);
231         return this;
232      }
233
234      @Override /* Overridden from Builder */
235      public Builder resolver(VarResolverSession value) {
236         super.resolver(value);
237         return this;
238      }
239
240      @Override /* Overridden from Builder */
241      public Builder schema(HttpPartSchema value) {
242         super.schema(value);
243         return this;
244      }
245
246      @Override /* Overridden from Builder */
247      public Builder schemaDefault(HttpPartSchema value) {
248         super.schemaDefault(value);
249         return this;
250      }
251
252      @Override /* Overridden from Builder */
253      public Builder uriContext(UriContext value) {
254         super.uriContext(value);
255         return this;
256      }
257   }
258
259   //-----------------------------------------------------------------------------------------------------------------
260   // Instance
261   //-----------------------------------------------------------------------------------------------------------------
262
263   private final WriterSerializer ctx;
264   private final boolean useWhitespace;
265   private final Charset streamCharset, fileCharset;
266
267   /**
268    * Constructor.
269    *
270    * @param builder The builder for this object.
271    */
272   protected WriterSerializerSession(Builder builder) {
273      super(builder);
274      ctx = builder.ctx;
275      streamCharset = builder.streamCharset;
276      fileCharset = builder.fileCharset;
277      useWhitespace = builder.useWhitespace;
278   }
279
280   @Override /* SerializerSession */
281   public final boolean isWriterSerializer() {
282      return true;
283   }
284
285   @Override /* SerializerSession */
286   protected SerializerPipe createPipe(Object output) {
287      return new SerializerPipe(output, streamCharset, fileCharset);
288   }
289
290   /**
291    * Convenience method for serializing an object to a <c>String</c>.
292    *
293    * @param o The object to serialize.
294    * @return The output serialized to a string.
295    * @throws SerializeException If a problem occurred trying to convert the output.
296    */
297   @Override /* SerializerSession */
298   public final String serialize(Object o) throws SerializeException {
299      StringWriter w = new StringWriter();
300      try {
301         serialize(o, w);
302      } catch (IOException e) {
303         throw new SerializeException(e); // Shouldn't happen.
304      }
305      return w.toString();
306   }
307
308   @Override /* SerializerSession */
309   public final String serializeToString(Object o) throws SerializeException {
310      return serialize(o);
311   }
312
313   //-----------------------------------------------------------------------------------------------------------------
314   // Properties
315   //-----------------------------------------------------------------------------------------------------------------
316
317   /**
318    * Maximum indentation.
319    *
320    * @see WriterSerializer.Builder#maxIndent(int)
321    * @return
322    *    The maximum indentation level in the serialized document.
323    */
324   protected final int getMaxIndent() {
325      return ctx.getMaxIndent();
326   }
327
328   /**
329    * Quote character.
330    *
331    * @see WriterSerializer.Builder#quoteChar(char)
332    * @return
333    *    The character used for quoting attributes and values.
334    */
335   protected char getQuoteChar() {
336      return ctx.getQuoteChar();
337   }
338
339   /**
340    * Use whitespace.
341    *
342    * @see WriterSerializer.Builder#useWhitespace()
343    * @return
344    *    The character used for quoting attributes and values.
345    */
346   protected final boolean isUseWhitespace() {
347      return useWhitespace;
348   }
349
350   /**
351    * Returns the file charset defined on this session.
352    *
353    * @return the file charset defined on this session.
354    */
355   public Charset getFileCharset() {
356      return fileCharset;
357   }
358
359   /**
360    * Returns the stream charset defined on this session.
361    *
362    * @return the stream charset defined on this session.
363    */
364   public Charset getStreamCharset() {
365      return streamCharset;
366   }
367
368   //-----------------------------------------------------------------------------------------------------------------
369   // Other methods
370   //-----------------------------------------------------------------------------------------------------------------
371
372   @Override /* ContextSession */
373   protected JsonMap properties() {
374      return filteredMap("fileCharset", fileCharset, "streamCharset", streamCharset, "useWhitespace", useWhitespace);
375   }
376}