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