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.plaintext;
018
019import static org.apache.juneau.commons.utils.AssertionUtils.*;
020
021import java.lang.annotation.*;
022import java.nio.charset.*;
023import java.util.*;
024import java.util.concurrent.*;
025
026import org.apache.juneau.*;
027import org.apache.juneau.commons.collections.*;
028import org.apache.juneau.commons.function.*;
029import org.apache.juneau.commons.reflect.*;
030import org.apache.juneau.serializer.*;
031import org.apache.juneau.swap.*;
032
033/**
034 * Serializes POJOs to plain text using just the <c>toString()</c> method on the serialized object.
035 *
036 * <h5 class='topic'>Media types</h5>
037 *
038 * Handles <c>Accept</c> types:  <bc>text/plain</bc>
039 * <p>
040 * Produces <c>Content-Type</c> types:  <bc>text/plain</bc>
041 *
042 * <h5 class='topic'>Description</h5>
043 *
044 * Essentially converts POJOs to plain text using the <c>toString()</c> method.
045 *
046 * <p>
047 * Also serializes objects using a transform if the object class has an {@link ObjectSwap ObjectSwap&lt;?,String&gt;}
048 * transform defined on it.
049 *
050 * <h5 class='section'>Notes:</h5><ul>
051 *    <li class='note'>This class is thread safe and reusable.
052 * </ul>
053 *
054 */
055public class PlainTextSerializer extends WriterSerializer implements PlainTextMetaProvider {
056   /**
057    * Builder class.
058    */
059   public static class Builder extends WriterSerializer.Builder {
060
061      private static final Cache<HashKey,PlainTextSerializer> CACHE = Cache.of(HashKey.class, PlainTextSerializer.class).build();
062
063      /**
064       * Constructor, default settings.
065       */
066      protected Builder() {
067         produces("text/plain");
068      }
069
070      /**
071       * Copy constructor.
072       *
073       * @param copyFrom The builder to copy from.
074       *    <br>Cannot be <jk>null</jk>.
075       */
076      protected Builder(Builder copyFrom) {
077         super(assertArgNotNull("copyFrom", copyFrom));
078      }
079
080      /**
081       * Copy constructor.
082       *
083       * @param copyFrom The bean to copy from.
084       *    <br>Cannot be <jk>null</jk>.
085       */
086      protected Builder(PlainTextSerializer copyFrom) {
087         super(assertArgNotNull("copyFrom", copyFrom));
088      }
089
090      @Override /* Overridden from Builder */
091      public Builder accept(String value) {
092         super.accept(value);
093         return this;
094      }
095
096      @Override /* Overridden from Builder */
097      public Builder addBeanTypes() {
098         super.addBeanTypes();
099         return this;
100      }
101
102      @Override /* Overridden from Builder */
103      public Builder addBeanTypes(boolean value) {
104         super.addBeanTypes(value);
105         return this;
106      }
107
108      @Override /* Overridden from Builder */
109      public Builder addRootType() {
110         super.addRootType();
111         return this;
112      }
113
114      @Override /* Overridden from Builder */
115      public Builder addRootType(boolean value) {
116         super.addRootType(value);
117         return this;
118      }
119
120      @Override /* Overridden from Builder */
121      public Builder annotations(Annotation...values) {
122         super.annotations(values);
123         return this;
124      }
125
126      @Override /* Overridden from Builder */
127      public Builder apply(AnnotationWorkList work) {
128         super.apply(work);
129         return this;
130      }
131
132      @Override /* Overridden from Builder */
133      public Builder applyAnnotations(Class<?>...from) {
134         super.applyAnnotations(from);
135         return this;
136      }
137
138      @Override /* Overridden from Builder */
139      public Builder applyAnnotations(Object...from) {
140         super.applyAnnotations(from);
141         return this;
142      }
143
144      @Override /* Overridden from Builder */
145      public Builder beanClassVisibility(Visibility value) {
146         super.beanClassVisibility(value);
147         return this;
148      }
149
150      @Override /* Overridden from Builder */
151      public Builder beanConstructorVisibility(Visibility value) {
152         super.beanConstructorVisibility(value);
153         return this;
154      }
155
156      @Override /* Overridden from Builder */
157      public Builder beanContext(BeanContext value) {
158         super.beanContext(value);
159         return this;
160      }
161
162      @Override /* Overridden from Builder */
163      public Builder beanContext(BeanContext.Builder value) {
164         super.beanContext(value);
165         return this;
166      }
167
168      @Override /* Overridden from Builder */
169      public Builder beanDictionary(java.lang.Class<?>...values) {
170         super.beanDictionary(values);
171         return this;
172      }
173
174      @Override /* Overridden from Builder */
175      public Builder beanFieldVisibility(Visibility value) {
176         super.beanFieldVisibility(value);
177         return this;
178      }
179
180      @Override /* Overridden from Builder */
181      public Builder beanInterceptor(Class<?> on, Class<? extends org.apache.juneau.swap.BeanInterceptor<?>> value) {
182         super.beanInterceptor(on, value);
183         return this;
184      }
185
186      @Override /* Overridden from Builder */
187      public Builder beanMapPutReturnsOldValue() {
188         super.beanMapPutReturnsOldValue();
189         return this;
190      }
191
192      @Override /* Overridden from Builder */
193      public Builder beanMethodVisibility(Visibility value) {
194         super.beanMethodVisibility(value);
195         return this;
196      }
197
198      @Override /* Overridden from Builder */
199      public Builder beanProperties(Class<?> beanClass, String properties) {
200         super.beanProperties(beanClass, properties);
201         return this;
202      }
203
204      @Override /* Overridden from Builder */
205      public Builder beanProperties(Map<String,Object> values) {
206         super.beanProperties(values);
207         return this;
208      }
209
210      @Override /* Overridden from Builder */
211      public Builder beanProperties(String beanClassName, String properties) {
212         super.beanProperties(beanClassName, properties);
213         return this;
214      }
215
216      @Override /* Overridden from Builder */
217      public Builder beanPropertiesExcludes(Class<?> beanClass, String properties) {
218         super.beanPropertiesExcludes(beanClass, properties);
219         return this;
220      }
221
222      @Override /* Overridden from Builder */
223      public Builder beanPropertiesExcludes(Map<String,Object> values) {
224         super.beanPropertiesExcludes(values);
225         return this;
226      }
227
228      @Override /* Overridden from Builder */
229      public Builder beanPropertiesExcludes(String beanClassName, String properties) {
230         super.beanPropertiesExcludes(beanClassName, properties);
231         return this;
232      }
233
234      @Override /* Overridden from Builder */
235      public Builder beanPropertiesReadOnly(Class<?> beanClass, String properties) {
236         super.beanPropertiesReadOnly(beanClass, properties);
237         return this;
238      }
239
240      @Override /* Overridden from Builder */
241      public Builder beanPropertiesReadOnly(Map<String,Object> values) {
242         super.beanPropertiesReadOnly(values);
243         return this;
244      }
245
246      @Override /* Overridden from Builder */
247      public Builder beanPropertiesReadOnly(String beanClassName, String properties) {
248         super.beanPropertiesReadOnly(beanClassName, properties);
249         return this;
250      }
251
252      @Override /* Overridden from Builder */
253      public Builder beanPropertiesWriteOnly(Class<?> beanClass, String properties) {
254         super.beanPropertiesWriteOnly(beanClass, properties);
255         return this;
256      }
257
258      @Override /* Overridden from Builder */
259      public Builder beanPropertiesWriteOnly(Map<String,Object> values) {
260         super.beanPropertiesWriteOnly(values);
261         return this;
262      }
263
264      @Override /* Overridden from Builder */
265      public Builder beanPropertiesWriteOnly(String beanClassName, String properties) {
266         super.beanPropertiesWriteOnly(beanClassName, properties);
267         return this;
268      }
269
270      @Override /* Overridden from Builder */
271      public Builder beansRequireDefaultConstructor() {
272         super.beansRequireDefaultConstructor();
273         return this;
274      }
275
276      @Override /* Overridden from Builder */
277      public Builder beansRequireSerializable() {
278         super.beansRequireSerializable();
279         return this;
280      }
281
282      @Override /* Overridden from Builder */
283      public Builder beansRequireSettersForGetters() {
284         super.beansRequireSettersForGetters();
285         return this;
286      }
287
288      @Override /* Overridden from Context.Builder */
289      public PlainTextSerializer build() {
290         return cache(CACHE).build(PlainTextSerializer.class);
291      }
292
293      @Override /* Overridden from Builder */
294      public Builder cache(Cache<HashKey,? extends org.apache.juneau.Context> value) {
295         super.cache(value);
296         return this;
297      }
298
299      @Override /* Overridden from Context.Builder */
300      public Builder copy() {
301         return new Builder(this);
302      }
303
304      @Override /* Overridden from Builder */
305      public Builder debug() {
306         super.debug();
307         return this;
308      }
309
310      @Override /* Overridden from Builder */
311      public Builder debug(boolean value) {
312         super.debug(value);
313         return this;
314      }
315
316      @Override /* Overridden from Builder */
317      public Builder detectRecursions() {
318         super.detectRecursions();
319         return this;
320      }
321
322      @Override /* Overridden from Builder */
323      public Builder detectRecursions(boolean value) {
324         super.detectRecursions(value);
325         return this;
326      }
327
328      @Override /* Overridden from Builder */
329      public Builder dictionaryOn(Class<?> on, java.lang.Class<?>...values) {
330         super.dictionaryOn(on, values);
331         return this;
332      }
333
334      @Override /* Overridden from Builder */
335      public Builder disableBeansRequireSomeProperties() {
336         super.disableBeansRequireSomeProperties();
337         return this;
338      }
339
340      @Override /* Overridden from Builder */
341      public Builder disableIgnoreMissingSetters() {
342         super.disableIgnoreMissingSetters();
343         return this;
344      }
345
346      @Override /* Overridden from Builder */
347      public Builder disableIgnoreTransientFields() {
348         super.disableIgnoreTransientFields();
349         return this;
350      }
351
352      @Override /* Overridden from Builder */
353      public Builder disableIgnoreUnknownNullBeanProperties() {
354         super.disableIgnoreUnknownNullBeanProperties();
355         return this;
356      }
357
358      @Override /* Overridden from Builder */
359      public Builder disableInterfaceProxies() {
360         super.disableInterfaceProxies();
361         return this;
362      }
363
364      @Override /* Overridden from Builder */
365      public <T> Builder example(Class<T> pojoClass, String json) {
366         super.example(pojoClass, json);
367         return this;
368      }
369
370      @Override /* Overridden from Builder */
371      public <T> Builder example(Class<T> pojoClass, T o) {
372         super.example(pojoClass, o);
373         return this;
374      }
375
376      @Override /* Overridden from Builder */
377      public Builder fileCharset(Charset value) {
378         super.fileCharset(value);
379         return this;
380      }
381
382      @Override /* Overridden from Builder */
383      public Builder findFluentSetters() {
384         super.findFluentSetters();
385         return this;
386      }
387
388      @Override /* Overridden from Builder */
389      public Builder findFluentSetters(Class<?> on) {
390         super.findFluentSetters(on);
391         return this;
392      }
393
394      @Override /* Overridden from Context.Builder */
395      public HashKey hashKey() {
396         return super.hashKey();
397      }
398
399      @Override /* Overridden from Builder */
400      public Builder ignoreInvocationExceptionsOnGetters() {
401         super.ignoreInvocationExceptionsOnGetters();
402         return this;
403      }
404
405      @Override /* Overridden from Builder */
406      public Builder ignoreInvocationExceptionsOnSetters() {
407         super.ignoreInvocationExceptionsOnSetters();
408         return this;
409      }
410
411      @Override /* Overridden from Builder */
412      public Builder ignoreRecursions() {
413         super.ignoreRecursions();
414         return this;
415      }
416
417      @Override /* Overridden from Builder */
418      public Builder ignoreRecursions(boolean value) {
419         super.ignoreRecursions(value);
420         return this;
421      }
422
423      @Override /* Overridden from Builder */
424      public Builder ignoreUnknownBeanProperties() {
425         super.ignoreUnknownBeanProperties();
426         return this;
427      }
428
429      @Override /* Overridden from Builder */
430      public Builder ignoreUnknownEnumValues() {
431         super.ignoreUnknownEnumValues();
432         return this;
433      }
434
435      @Override /* Overridden from Builder */
436      public Builder impl(Context value) {
437         super.impl(value);
438         return this;
439      }
440
441      @Override /* Overridden from Builder */
442      public Builder implClass(Class<?> interfaceClass, Class<?> implClass) {
443         super.implClass(interfaceClass, implClass);
444         return this;
445      }
446
447      @Override /* Overridden from Builder */
448      public Builder implClasses(Map<Class<?>,Class<?>> values) {
449         super.implClasses(values);
450         return this;
451      }
452
453      @Override /* Overridden from Builder */
454      public Builder initialDepth(int value) {
455         super.initialDepth(value);
456         return this;
457      }
458
459      @Override /* Overridden from Builder */
460      public Builder interfaceClass(Class<?> on, Class<?> value) {
461         super.interfaceClass(on, value);
462         return this;
463      }
464
465      @Override /* Overridden from Builder */
466      public Builder interfaces(java.lang.Class<?>...value) {
467         super.interfaces(value);
468         return this;
469      }
470
471      @Override /* Overridden from Builder */
472      public Builder keepNullProperties() {
473         super.keepNullProperties();
474         return this;
475      }
476
477      @Override /* Overridden from Builder */
478      public Builder keepNullProperties(boolean value) {
479         super.keepNullProperties(value);
480         return this;
481      }
482
483      @Override /* Overridden from Builder */
484      public Builder listener(Class<? extends org.apache.juneau.serializer.SerializerListener> value) {
485         super.listener(value);
486         return this;
487      }
488
489      @Override /* Overridden from Builder */
490      public Builder locale(Locale value) {
491         super.locale(value);
492         return this;
493      }
494
495      @Override /* Overridden from Builder */
496      public Builder maxDepth(int value) {
497         super.maxDepth(value);
498         return this;
499      }
500
501      @Override /* Overridden from Builder */
502      public Builder maxIndent(int value) {
503         super.maxIndent(value);
504         return this;
505      }
506
507      @Override /* Overridden from Builder */
508      public Builder mediaType(MediaType value) {
509         super.mediaType(value);
510         return this;
511      }
512
513      @Override /* Overridden from Builder */
514      public Builder notBeanClasses(java.lang.Class<?>...values) {
515         super.notBeanClasses(values);
516         return this;
517      }
518
519      @Override /* Overridden from Builder */
520      public Builder notBeanPackages(String...values) {
521         super.notBeanPackages(values);
522         return this;
523      }
524
525      @Override /* Overridden from Builder */
526      public Builder produces(String value) {
527         super.produces(value);
528         return this;
529      }
530
531      @Override /* Overridden from Builder */
532      public Builder propertyNamer(Class<?> on, Class<? extends org.apache.juneau.PropertyNamer> value) {
533         super.propertyNamer(on, value);
534         return this;
535      }
536
537      @Override /* Overridden from Builder */
538      public Builder propertyNamer(Class<? extends org.apache.juneau.PropertyNamer> value) {
539         super.propertyNamer(value);
540         return this;
541      }
542
543      @Override /* Overridden from Builder */
544      public Builder quoteChar(char value) {
545         super.quoteChar(value);
546         return this;
547      }
548
549      @Override /* Overridden from Builder */
550      public Builder quoteCharOverride(char value) {
551         super.quoteCharOverride(value);
552         return this;
553      }
554
555      @Override /* Overridden from Builder */
556      public Builder sortCollections() {
557         super.sortCollections();
558         return this;
559      }
560
561      @Override /* Overridden from Builder */
562      public Builder sortCollections(boolean value) {
563         super.sortCollections(value);
564         return this;
565      }
566
567      @Override /* Overridden from Builder */
568      public Builder sortMaps() {
569         super.sortMaps();
570         return this;
571      }
572
573      @Override /* Overridden from Builder */
574      public Builder sortMaps(boolean value) {
575         super.sortMaps(value);
576         return this;
577      }
578
579      @Override /* Overridden from Builder */
580      public Builder sortProperties() {
581         super.sortProperties();
582         return this;
583      }
584
585      @Override /* Overridden from Builder */
586      public Builder sortProperties(java.lang.Class<?>...on) {
587         super.sortProperties(on);
588         return this;
589      }
590
591      @Override /* Overridden from Builder */
592      public Builder sq() {
593         super.sq();
594         return this;
595      }
596
597      @Override /* Overridden from Builder */
598      public Builder stopClass(Class<?> on, Class<?> value) {
599         super.stopClass(on, value);
600         return this;
601      }
602
603      @Override /* Overridden from Builder */
604      public Builder streamCharset(Charset value) {
605         super.streamCharset(value);
606         return this;
607      }
608
609      @Override /* Overridden from Builder */
610      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction) {
611         super.swap(normalClass, swappedClass, swapFunction);
612         return this;
613      }
614
615      @Override /* Overridden from Builder */
616      public <T,S> Builder swap(Class<T> normalClass, Class<S> swappedClass, ThrowingFunction<T,S> swapFunction, ThrowingFunction<S,T> unswapFunction) {
617         super.swap(normalClass, swappedClass, swapFunction, unswapFunction);
618         return this;
619      }
620
621      @Override /* Overridden from Builder */
622      public Builder swaps(Class<?>...values) {
623         super.swaps(values);
624         return this;
625      }
626
627      @Override /* Overridden from Builder */
628      public Builder swaps(Object...values) {
629         super.swaps(values);
630         return this;
631      }
632
633      @Override /* Overridden from Builder */
634      public Builder timeZone(TimeZone value) {
635         super.timeZone(value);
636         return this;
637      }
638
639      @Override /* Overridden from Builder */
640      public Builder trimEmptyCollections() {
641         super.trimEmptyCollections();
642         return this;
643      }
644
645      @Override /* Overridden from Builder */
646      public Builder trimEmptyCollections(boolean value) {
647         super.trimEmptyCollections(value);
648         return this;
649      }
650
651      @Override /* Overridden from Builder */
652      public Builder trimEmptyMaps() {
653         super.trimEmptyMaps();
654         return this;
655      }
656
657      @Override /* Overridden from Builder */
658      public Builder trimEmptyMaps(boolean value) {
659         super.trimEmptyMaps(value);
660         return this;
661      }
662
663      @Override /* Overridden from Builder */
664      public Builder trimStrings() {
665         super.trimStrings();
666         return this;
667      }
668
669      @Override /* Overridden from Builder */
670      public Builder trimStrings(boolean value) {
671         super.trimStrings(value);
672         return this;
673      }
674
675      @Override /* Overridden from Builder */
676      public Builder type(Class<? extends org.apache.juneau.Context> value) {
677         super.type(value);
678         return this;
679      }
680
681      @Override /* Overridden from Builder */
682      public Builder typeName(Class<?> on, String value) {
683         super.typeName(on, value);
684         return this;
685      }
686
687      @Override /* Overridden from Builder */
688      public Builder typePropertyName(Class<?> on, String value) {
689         super.typePropertyName(on, value);
690         return this;
691      }
692
693      @Override /* Overridden from Builder */
694      public Builder typePropertyName(String value) {
695         super.typePropertyName(value);
696         return this;
697      }
698
699      @Override /* Overridden from Builder */
700      public Builder uriContext(UriContext value) {
701         super.uriContext(value);
702         return this;
703      }
704
705      @Override /* Overridden from Builder */
706      public Builder uriRelativity(UriRelativity value) {
707         super.uriRelativity(value);
708         return this;
709      }
710
711      @Override /* Overridden from Builder */
712      public Builder uriResolution(UriResolution value) {
713         super.uriResolution(value);
714         return this;
715      }
716
717      @Override /* Overridden from Builder */
718      public Builder useEnumNames() {
719         super.useEnumNames();
720         return this;
721      }
722
723      @Override /* Overridden from Builder */
724      public Builder useJavaBeanIntrospector() {
725         super.useJavaBeanIntrospector();
726         return this;
727      }
728
729      @Override /* Overridden from Builder */
730      public Builder useWhitespace() {
731         super.useWhitespace();
732         return this;
733      }
734
735      @Override /* Overridden from Builder */
736      public Builder useWhitespace(boolean value) {
737         super.useWhitespace(value);
738         return this;
739      }
740
741      @Override /* Overridden from Builder */
742      public Builder ws() {
743         super.ws();
744         return this;
745      }
746   }
747
748   /** Default serializer, all default settings.*/
749   public static final PlainTextSerializer DEFAULT = new PlainTextSerializer(create());
750
751   /**
752    * Creates a new builder for this object.
753    *
754    * @return A new builder.
755    */
756   public static Builder create() {
757      return new Builder();
758   }
759
760   private final Map<ClassMeta<?>,PlainTextClassMeta> plainTextClassMetas = new ConcurrentHashMap<>();
761   private final Map<BeanPropertyMeta,PlainTextBeanPropertyMeta> plainTextBeanPropertyMetas = new ConcurrentHashMap<>();
762
763   /**
764    * Constructor.
765    *
766    * @param builder
767    *    The builder for this object.
768    */
769   public PlainTextSerializer(Builder builder) {
770      super(builder);
771   }
772
773   @Override /* Overridden from Context */
774   public Builder copy() {
775      return new Builder(this);
776   }
777
778   @Override /* Overridden from Context */
779   public PlainTextSerializerSession.Builder createSession() {
780      return PlainTextSerializerSession.create(this);
781   }
782
783   @Override /* Overridden from PlainTextMetaProvider */
784   public PlainTextBeanPropertyMeta getPlainTextBeanPropertyMeta(BeanPropertyMeta bpm) {
785      if (bpm == null)
786         return PlainTextBeanPropertyMeta.DEFAULT;
787      var m = plainTextBeanPropertyMetas.get(bpm);
788      if (m == null) {
789         m = new PlainTextBeanPropertyMeta(bpm.getDelegateFor(), this);
790         plainTextBeanPropertyMetas.put(bpm, m);
791      }
792      return m;
793   }
794
795   @Override /* Overridden from PlainTextMetaProvider */
796   public PlainTextClassMeta getPlainTextClassMeta(ClassMeta<?> cm) {
797      var m = plainTextClassMetas.get(cm);
798      if (m == null) {
799         m = new PlainTextClassMeta(cm, this);
800         plainTextClassMetas.put(cm, m);
801      }
802      return m;
803   }
804
805   @Override /* Overridden from Context */
806   public PlainTextSerializerSession getSession() { return createSession().build(); }
807}