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