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.plaintext;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.io.*;
022import java.util.*;
023import java.util.concurrent.*;
024
025import org.apache.juneau.commons.bean.*;
026import org.apache.juneau.commons.collections.*;
027import org.apache.juneau.marshall.*;
028import org.apache.juneau.marshall.serializer.*;
029import org.apache.juneau.marshall.stream.*;
030import org.apache.juneau.marshall.swap.spi.*;
031
032/**
033 * Serializes POJOs to plain text using just the <c>toString()</c> method on the serialized object.
034 *
035 * <h5 class='topic'>Media types</h5>
036 *
037 * Handles <c>Accept</c> types:  <bc>text/plain</bc>
038 * <p>
039 * Produces <c>Content-Type</c> types:  <bc>text/plain</bc>
040 *
041 * <h5 class='topic'>Description</h5>
042 *
043 * Essentially converts POJOs to plain text using the <c>toString()</c> method.
044 *
045 * <p>
046 * Also serializes objects using a transform if the object class has an {@link ObjectSwap ObjectSwap&lt;?,String&gt;}
047 * transform defined on it.
048 *
049 * <h5 class='section'>Notes:</h5><ul>
050 *    <li class='note'>This class is thread safe and reusable.
051 * </ul>
052 *
053 */
054@SuppressWarnings({
055   "java:S110", // Inheritance depth acceptable for this class hierarchy
056   "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants
057   "java:S9149", // Per-format static factories intentionally shadow the parent's.
058   "resource" // Closeable resources are owned by the caller's serializer session; Eclipse JDT @Owning warning is by design.
059})
060public class PlainTextSerializer extends WriterSerializer implements PlainTextMetaProvider, RecordWritable {
061
062   /**
063    * Builder class.
064    */
065   public static class Builder extends WriterSerializer.Builder<Builder> {
066
067      private static final Cache<HashKey,PlainTextSerializer> CACHE = Cache.of(HashKey.class, PlainTextSerializer.class).build();
068
069      /**
070       * Constructor, default settings.
071       */
072      protected Builder() {
073         produces("text/plain");
074      }
075
076      /**
077       * Copy constructor.
078       *
079       * @param copyFrom The builder to copy from.
080       *    <br>Cannot be <jk>null</jk>.
081       */
082      protected Builder(Builder copyFrom) {
083         super(reqnn("copyFrom", copyFrom));
084      }
085
086      /**
087       * Copy constructor.
088       *
089       * @param copyFrom The bean to copy from.
090       *    <br>Cannot be <jk>null</jk>.
091       */
092      protected Builder(PlainTextSerializer copyFrom) {
093         super(reqnn("copyFrom", copyFrom));
094      }
095
096      @Override /* Overridden from Context.Builder<?> */
097      public PlainTextSerializer build() {
098         return cache(CACHE).build(PlainTextSerializer.class);
099      }
100
101      @Override /* Overridden from Context.Builder<?> */
102      public Builder copy() {
103         return new Builder(this);
104      }
105
106
107   }
108
109   /** Default serializer, all default settings.*/
110   public static final PlainTextSerializer DEFAULT = new PlainTextSerializer(create());
111
112   /**
113    * Creates a new builder for this object.
114    *
115    * @return A new builder.
116    */
117   public static Builder create() {
118      return new Builder();
119   }
120
121   private final Map<ClassMeta<?>,PlainTextClassMeta> plainTextClassMetas = new ConcurrentHashMap<>();
122   private final Map<BeanPropertyMeta,PlainTextBeanPropertyMeta> plainTextBeanPropertyMetas = new ConcurrentHashMap<>();
123
124   /**
125    * Constructor.
126    *
127    * @param builder
128    *    The builder for this object.
129    */
130   public PlainTextSerializer(Builder builder) {
131      super(builder);
132   }
133
134   @Override /* Overridden from Context */
135   public Builder copy() {
136      return new Builder(this);
137   }
138
139   @Override /* Overridden from Context */
140   public PlainTextSerializerSession.Builder createSession() {
141      return PlainTextSerializerSession.create(this);
142   }
143
144   @Override /* Overridden from PlainTextMetaProvider */
145   public PlainTextBeanPropertyMeta getPlainTextBeanPropertyMeta(BeanPropertyMeta bpm) {
146      if (bpm == null)
147         return PlainTextBeanPropertyMeta.DEFAULT;
148      return plainTextBeanPropertyMetas.computeIfAbsent(bpm, k -> new PlainTextBeanPropertyMeta(k.getDelegateFor(), this));
149   }
150
151   @Override /* Overridden from PlainTextMetaProvider */
152   public PlainTextClassMeta getPlainTextClassMeta(ClassMeta<?> cm) {
153      return plainTextClassMetas.computeIfAbsent(cm, k -> new PlainTextClassMeta(k, this));
154   }
155
156   @Override /* Overridden from Context */
157   public PlainTextSerializerSession getSession() { return createSession().build(); }
158
159   /**
160    * Convenience delegator that opens a {@link RecordWriter} over the output using
161    * <b>default session arguments</b> (mirrors {@link #write(Object)}).
162    *
163    * <p>
164    * The real implementation lives on {@link PlainTextSerializerSession#writeRecords(Object)}.
165    * Callers that need request-derived configuration should call {@link #createSession()} and
166    * invoke {@link PlainTextSerializerSession#writeRecords(Object)} on the built session instead.
167    *
168    * @param output The output.
169    * @return A new {@link RecordWriter}.
170    * @throws IOException If a problem occurred opening the underlying output.
171    */
172   @Override /* RecordWritable */
173   public RecordWriter writeRecords(Object output) throws IOException {
174      return getSession().writeRecords(output);
175   }
176
177   @Override /* RecordWritable */
178   public boolean isRecordStreaming() {
179      return false;
180   }
181}