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