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