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