View Javadoc
1   package org.andromda.cartridges.support.webservice.client;
2   
3   import java.lang.reflect.Array;
4   import java.lang.reflect.Method;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.HashMap;
8   import java.util.Iterator;
9   import java.util.List;
10  import java.util.Map;
11  import javax.wsdl.Definition;
12  import javax.wsdl.Types;
13  import javax.wsdl.extensions.schema.Schema;
14  import javax.xml.namespace.QName;
15  import org.apache.axiom.om.OMAbstractFactory;
16  import org.apache.axiom.om.OMElement;
17  import org.apache.axiom.om.OMFactory;
18  import org.apache.axiom.om.OMNamespace;
19  import org.apache.axiom.util.base64.Base64Utils;
20  import org.apache.commons.beanutils.PropertyUtils;
21  import org.apache.commons.lang.StringUtils;
22  import org.w3c.dom.Element;
23  import org.w3c.dom.Node;
24  import org.w3c.dom.NodeList;
25  
26  /**
27   * Utilities for Axis2 clients.
28   *
29   * @author Chad Brandon
30   */
31  public class Axis2ClientUtils
32  {
33      /**
34       * Gets the appropriate OM element for the given method
35       * @param definition the WSDL definition.
36       * @param method the method corresponding to the OMElement to create.
37       * @param arguments the arguments to pass to the method.
38       * @param typeMapper the {@link TypeMapper} instance to use for converting types.
39       * @return the constructed OMElement
40       */
41      public static OMElement getOperationOMElement(
42          final Definition definition,
43          final Method method,
44          final Object[] arguments,
45          final TypeMapper typeMapper)
46      {
47          final Class serviceClass = method.getDeclaringClass();
48          OMElement operationOMElement = null;
49          try
50          {
51              final String operationName = method.getName();
52              final String serviceName = serviceClass.getSimpleName();
53              final Element operationElement = getElementByAttribute(
54                      definition,
55                      NAME,
56                      operationName);
57              final Schema operationSchema = Axis2ClientUtils.getElementSchemaByAttribute(
58                      definition,
59                      NAME,
60                      operationName);
61              if (operationSchema != null)
62              {
63                  final OMFactory factory = OMAbstractFactory.getOMFactory();
64  
65                  // - collect all the namespaces
66                  final Map<String, OMNamespace> namespaces = new HashMap<String, OMNamespace>();
67                  final OMNamespace xsiNamespace = factory.createOMNamespace(XSI_NS, XSI_PREFIX);
68                  namespaces.put(XSI_PREFIX, xsiNamespace);
69  
70                  final Collection<Schema> schemas = getSchemas(definition);
71                  for (final Schema schema : schemas)
72                  {
73                      final String namespace = Axis2ClientUtils.getTargetNamespace(schema);
74                      final String prefix = getNamespacePrefix(
75                              definition,
76                              namespace);
77                      namespaces.put(prefix, factory.createOMNamespace(namespace, prefix));
78                  }
79  
80                  operationOMElement =
81                      getOMElement(
82                          definition,
83                          operationSchema,
84                          null,
85                          null,
86                          operationName,
87                          factory,
88                          namespaces,
89                          typeMapper);
90                  if (operationElement == null)
91                  {
92                      throw new RuntimeException("No operation with name '" + operationName + "' can be found on service: " +
93                          serviceName);
94                  }
95                  final List argumentElements = Axis2ClientUtils.getElementsWithAttribute(
96                          operationElement,
97                          TYPE);
98                  final Class[] parameterTypes = method.getParameterTypes();
99                  if (argumentElements.size() != arguments.length)
100                 {
101                     throw new RuntimeException("Operation: " + operationName + " takes " + parameterTypes.length +
102                         " argument(s), and 'arguments' only contains: " + arguments.length);
103                 }
104 
105                 // - declare all the namespaces
106                 operationOMElement.declareNamespace(xsiNamespace);
107                 for (final OMNamespace namespace : namespaces.values())
108                 {
109                     operationOMElement.declareNamespace(namespace);
110                 }
111 
112                 // - add the argument children
113                 for (int ctr = 0; ctr < argumentElements.size(); ctr++)
114                 {
115                     final Element argument = (Element)argumentElements.get(ctr);
116                     final String argumentName = getAttributeValue(
117                             argument,
118                             NAME);
119                     final OMElement element = getOMElement(
120                             definition,
121                             operationSchema,
122                             argument,
123                             arguments[ctr],
124                             argumentName,
125                             factory,
126                             namespaces,
127                             typeMapper);
128                     operationOMElement.addChild(element);
129                 }
130             }
131         }
132         catch (Exception exception)
133         {
134             throw new RuntimeException(exception);
135         }
136         return operationOMElement;
137     }
138 
139     /**
140      * Constructs and OMElement from the given bean
141      *
142      * @param definition the WSDL definition
143      * @param schema the current schema from which to retrieve the om element.
144      * @param componentElement the current componentElemnet of the WSDL definition.
145      * @param bean the bean to introspect
146      * @param elementName the name of the element to construct.
147      * @param factory the factory used for element construction.
148      * @param namespaces all available namespaces.
149      * @param typeMapper the {@link TypeMapper} instance to use for converting types.
150      * @return OMElement
151      */
152     public static OMElement getOMElement(
153         final Definition definition,
154         final Schema schema,
155         final Element componentElement,
156         final Object bean,
157         final String elementName,
158         final OMFactory factory,
159         final Map<String, OMNamespace> namespaces,
160         final TypeMapper typeMapper)
161     {
162         return getOMElement(
163             definition,
164             schema,
165             componentElement,
166             bean,
167             elementName,
168             factory,
169             namespaces,
170             typeMapper,
171             new ArrayList<Object>());
172     }
173 
174     /**
175      * Constructs and OMElement from the given bean
176      *
177      * @param definition the WSDL definition
178      * @param schema the current schema from which to retrieve the om element.
179      * @param componentElement the current componentElemnet of the WSDL definition.
180      * @param bean the bean to introspect
181      * @param elementName the name of the element
182      * @param factory the OM factory instance used to create the element.
183      * @param namespaces all available namespaces.
184      * @param typeMapper the {@link TypeMapper} instance to use for converting types.
185      * @param evaluatingBeans the collection in which to keep the beans that are evaluating in order
186      *        to prevent endless recursion.
187      */
188     private static OMElement getOMElement(
189         final Definition definition,
190         Schema schema,
191         final Element componentElement,
192         final Object bean,
193         final String elementName,
194         final OMFactory factory,
195         final Map<String, OMNamespace> namespaces,
196         final TypeMapper typeMapper,
197         final Collection<Object> evaluatingBeans)
198     {
199         final String componentElementName = componentElement != null ? componentElement.getAttribute(NAME) : null;
200         if (StringUtils.isNotBlank(componentElementName))
201         {
202             final Schema currentSchema = Axis2ClientUtils.getElementSchemaByAttribute(
203                     definition,
204                     NAME,
205                     componentElementName);
206             if (currentSchema != null)
207             {
208                 schema = currentSchema;
209             }
210         }
211 
212         OMNamespace omNamespace = null;
213         if (isQualified(schema))
214         {
215             final String namespace = Axis2ClientUtils.getTargetNamespace(schema);
216             final String namespacePrefix = getNamespacePrefix(
217                     definition,
218                     namespace);
219             omNamespace = namespaces.get(namespacePrefix);
220         }
221 
222         final OMElement omElement =
223             factory.createOMElement(
224                 elementName,
225                 omNamespace);
226         if (bean != null && evaluatingBeans != null && !evaluatingBeans.contains(bean))
227         {
228             evaluatingBeans.add(bean);
229             if (isSimpleType(bean, typeMapper))
230             {
231                 omElement.addChild(factory.createOMText(typeMapper.getStringValue(bean)));
232             }
233             else if (bean instanceof byte[])
234             {
235                 omElement.addChild(factory.createOMText(Base64Utils.encode((byte[])bean)));
236             }
237             else
238             {
239                 final Element currentComponentElement =
240                     Axis2ClientUtils.getElementByAttribute(
241                         definition,
242                         NAME,
243                         bean.getClass().getSimpleName());
244                 final Class beanType = bean.getClass();
245                 if (beanType.isArray())
246                 {
247                     final Element arrayElement = Axis2ClientUtils.getRequiredElementByAttribute(
248                             definition,
249                             componentElement,
250                             NAME,
251                             elementName);
252                     final Element arrayTypeElement =
253                         Axis2ClientUtils.getElementByAttribute(
254                             definition,
255                             NAME,
256                             stripPrefix(arrayElement.getAttribute(TYPE)));
257                     final String arrayComponentName = Axis2ClientUtils.getAttributeValueFromChildElement(
258                             arrayTypeElement,
259                             NAME,
260                             0);
261                     for (int ctr = 0; ctr < Array.getLength(bean); ctr++)
262                     {
263                         omElement.addChild(
264                             getOMElement(
265                                 definition,
266                                 schema,
267                                 currentComponentElement,
268                                 Array.get(
269                                     bean,
270                                     ctr),
271                                 arrayComponentName,
272                                 factory,
273                                 namespaces,
274                                 typeMapper,
275                                 evaluatingBeans));
276                     }
277                 }
278                 else
279                 {
280                     final String attributeValue = omNamespace != null ?
281                         omNamespace.getPrefix() + NS_SEPARATOR + beanType.getSimpleName() : beanType.getSimpleName();
282                     // - add the xsi:type attribute for complex types
283                     omElement.addAttribute(TYPE, attributeValue, namespaces.get(XSI_PREFIX));
284                 }
285                 try
286                 {
287                     final java.util.Map<String, Object> properties = PropertyUtils.describe(bean);
288                     for (final String name : properties.keySet())
289                     {
290                         if (!CLASS.equals(name))
291                         {
292                             final Object value = properties.get(name);
293                             if (value != null)
294                             {
295                                 omElement.addChild(
296                                         getOMElement(
297                                                 definition,
298                                                 schema,
299                                                 currentComponentElement,
300                                                 value,
301                                                 name,
302                                                 factory,
303                                                 namespaces,
304                                                 typeMapper,
305                                                 evaluatingBeans));
306                             }
307                         }
308                     }
309                 }
310                 catch (final Throwable throwable)
311                 {
312                     throw new RuntimeException(throwable);
313                 }
314             }
315             evaluatingBeans.remove(bean);
316         }
317         return omElement;
318     }
319 
320     private static final String ELEMENT_FORM_DEFAULT = "elementFormDefault";
321 
322     /**
323      * Indicates whether or not a xml document is qualified.
324      */
325     private static final String QUALIFIED = "qualified";
326 
327     /**
328      * The attribute that stores the target namespace.
329      */
330     private static final String TARGET_NAMESPACE = "targetNamespace";
331 
332     /**
333      * The schema instance namespace.
334      */
335     private static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
336 
337     /**
338      * The prefix for the schema instance namespace.
339      */
340     private static final String XSI_PREFIX = "xsi";
341 
342     /**
343      * Used to separate a namespace prefix and name in a QName.
344      */
345     private static final String NS_SEPARATOR = ":";
346 
347     /**
348      * Indicates whether or not the schema is qualified.
349      *
350      * @param schema the schema to check.
351      * @return true/false
352      */
353     private static boolean isQualified(Schema schema)
354     {
355         boolean isQualified = false;
356         if (schema != null)
357         {
358             final String qualified = Axis2ClientUtils.getAttributeValue(
359                 schema.getElement(),
360                 ELEMENT_FORM_DEFAULT);
361             isQualified = QUALIFIED.equalsIgnoreCase(qualified);
362         }
363         return isQualified;
364     }
365 
366     private static String getTargetNamespace(Schema schema)
367     {
368         return Axis2ClientUtils.getAttributeValue(
369             schema.getElement(),
370             TARGET_NAMESPACE);
371     }
372 
373     private static String stripPrefix(String name)
374     {
375         return name.replaceAll(
376             ".*:",
377             "");
378     }
379 
380     private static String getNamespacePrefix(
381         final Definition definition,
382         final String namespace)
383     {
384         String prefix = null;
385         final Map<String, String> namespaces = definition.getNamespaces();
386         for (Map.Entry<String, String> entry : namespaces.entrySet())
387         {
388             if (entry.getValue().equals(namespace))
389             {
390                 prefix = entry.getKey();
391             }
392         }
393         return prefix;
394     }
395 
396     private static final String NAME = "name";
397     private static final String TYPE = "type";
398     private static final String BASE = "base";
399 
400     private static Element getRequiredElementByAttribute(
401         final Definition definition,
402         final Element container,
403         final String attribute,
404         final String value)
405     {
406         Element element = null;
407         if (container != null)
408         {
409             element = Axis2ClientUtils.getElementByAttribute(
410                 container,
411                 attribute,
412                 value);
413         }
414         // - try finding the element on an inherited type
415         if (element == null)
416         {
417             final String xsiTypeName = Axis2ClientUtils.getAttributeValueFromChildElement(container, BASE, 0);
418             final String typeName = getLocalName(xsiTypeName);
419             element = Axis2ClientUtils.getElementByAttribute(
420                 Axis2ClientUtils.getElementByAttribute(definition, NAME, typeName),
421                 attribute,
422                 value);
423         }
424         if (element == null)
425         {
426             String attr = container==null ? "" : container.getAttribute(NAME);
427             throw new RuntimeException('\'' + value + "' was not found on element '" + attr + '\'');
428         }
429         return element;
430     }
431 
432     private static Element getElementByAttribute(
433         final Definition definition,
434         final String attribute,
435         final String value)
436     {
437         Element element = null;
438         if (value != null)
439         {
440             final Types types = definition.getTypes();
441             final Collection elements = types.getExtensibilityElements();
442             for (final Iterator iterator = elements.iterator(); iterator.hasNext();)
443             {
444                 final Object object = iterator.next();
445                 if (object instanceof Schema)
446                 {
447                     final Schema schema = (Schema)object;
448                     element =
449                         getElementByAttribute(
450                             schema.getElement(),
451                             attribute,
452                             value);
453                     if (element != null)
454                     {
455                         break;
456                     }
457                 }
458             }
459         }
460         return element;
461     }
462 
463     private static Collection<Schema> getSchemas(final Definition definition)
464     {
465         final Collection<Schema> schemas = new ArrayList<Schema>();
466         final Types types = definition.getTypes();
467         final Collection elements = types.getExtensibilityElements();
468         for (final Iterator iterator = elements.iterator(); iterator.hasNext();)
469         {
470             final Object object = iterator.next();
471             if (object instanceof Schema)
472             {
473                 schemas.add((Schema)object);
474             }
475         }
476         return schemas;
477     }
478 
479     private static Element getElementByAttribute(
480         final Schema schema,
481         final String attribute,
482         final String value)
483     {
484         return getElementByAttribute(
485             schema.getElement(),
486             attribute,
487             value);
488     }
489 
490     /**
491      * Gets the schema that owns the element that has the given attribute with the given value.
492      *
493      * @param definition the WSDL definition.
494      * @param attribute the name of the attribute to find.
495      * @param value the value of the attribute.
496      * @return the schema
497      */
498     private static Schema getElementSchemaByAttribute(
499         final Definition definition,
500         final String attribute,
501         final String value)
502     {
503         final Types types = definition.getTypes();
504         final Collection elements = types.getExtensibilityElements();
505         Schema schema = null;
506         for (final Iterator iterator = elements.iterator(); iterator.hasNext();)
507         {
508             final Object object = iterator.next();
509             if (object instanceof Schema)
510             {
511                 final Element element = getElementByAttribute(
512                         (Schema)object,
513                         attribute,
514                         value);
515                 if (element != null)
516                 {
517                     schema = (Schema)object;
518                     break;
519                 }
520             }
521         }
522         return schema;
523     }
524 
525     private static Element getElementByAttribute(
526         final Element element,
527         final String attribute,
528         final String value)
529     {
530         Element found = null;
531         if (element != null && value != null)
532         {
533             final String foundAttribute = element.getAttribute(attribute);
534             if (StringUtils.isNotBlank(value) && value.equals(foundAttribute))
535             {
536                 found = element;
537             }
538             else
539             {
540                 final NodeList nodes = element.getChildNodes();
541                 for (int ctr = 0; ctr < nodes.getLength(); ctr++)
542                 {
543                     final Node node = nodes.item(ctr);
544                     if (node instanceof Element)
545                     {
546                         found =
547                             getElementByAttribute(
548                                 (Element)node,
549                                 attribute,
550                                 value);
551                         if (found != null)
552                         {
553                             break;
554                         }
555                     }
556                 }
557             }
558         }
559         return found;
560     }
561 
562     private static List<Element> getElementsWithAttribute(
563         final Element element,
564         final String attribute)
565     {
566         final List<Element> found = new ArrayList<Element>();
567         if (element != null)
568         {
569             final String foundAttribute = element.getAttribute(attribute);
570             if (StringUtils.isNotBlank(foundAttribute))
571             {
572                 found.add(element);
573             }
574             final NodeList nodes = element.getChildNodes();
575             for (int ctr = 0; ctr < nodes.getLength(); ctr++)
576             {
577                 final Node node = nodes.item(ctr);
578                 if (node instanceof Element)
579                 {
580                     found.addAll(getElementsWithAttribute(
581                             (Element)node,
582                             attribute));
583                 }
584             }
585         }
586         return found;
587     }
588 
589     private static String getAttributeValue(
590         final Element element,
591         final String attribute)
592     {
593         String value = null;
594         Element found = getElementWithAttribute(
595                 element,
596                 attribute);
597         if (found != null)
598         {
599             value = found.getAttribute(attribute);
600         }
601         return value;
602     }
603 
604     private static String getAttributeValueFromChildElement(
605         final Element element,
606         final String attribute,
607         int childIndex)
608     {
609         String value = null;
610         if (element != null)
611         {
612             int elementIndex = 0;
613             for (int ctr = 0; ctr < element.getChildNodes().getLength(); ctr++)
614             {
615                 final Node node = element.getChildNodes().item(ctr);
616                 if (node instanceof Element)
617                 {
618                     if (elementIndex == childIndex)
619                     {
620                         value =
621                             getAttributeValue(
622                                 (Element)node,
623                                 attribute);
624                     }
625                     elementIndex++;
626                 }
627             }
628         }
629         return value;
630     }
631 
632     /**
633      * Finds the first child element of the given <code>element</code> that has an attribute
634      * matching the name of <code>attribute</code>.
635      *
636      * @param element the element to search.
637      * @param attribute the name of the attribute to get.
638      * @return the found element or null if not found.
639      */
640     private static Element getElementWithAttribute(
641         final Element element,
642         final String attribute)
643     {
644         Element found = null;
645         if (element != null)
646         {
647             final NodeList nodes = element.getChildNodes();
648             final String foundAttribute = element.getAttribute(attribute);
649             if (StringUtils.isNotBlank(foundAttribute))
650             {
651                 found = element;
652             }
653             if (found == null)
654             {
655                 for (int ctr = 0; ctr < nodes.getLength(); ctr++)
656                 {
657                     final Node node = nodes.item(ctr);
658                     if (node instanceof Element)
659                     {
660                         found =
661                             getElementWithAttribute(
662                                 (Element)node,
663                                 attribute);
664                     }
665                 }
666             }
667         }
668         return found;
669     }
670 
671     private static final String CLASS = "class";
672 
673     /**
674      * Deserializes the given <code>element</code> to the given <code>type</code>.
675      *
676      * @param element the XML OMElement
677      * @param type the java type.
678      * @param typeMapper the "object creator" used to construct objects from given classes.
679      * @return the deserialized object.
680      * @throws Exception
681      */
682     public static Object deserialize(
683         OMElement element,
684         Class type,
685         final TypeMapper typeMapper) throws Exception
686     {
687         Object bean = null;
688         if (typeMapper.isSimpleType(type))
689         {
690             bean = getSimpleTypeObject(type, element, typeMapper);
691         }
692         else if (type == byte[].class)
693         {
694             bean = Base64Utils.decode(element.getText());
695         }
696         else
697         {
698             if (type.isArray())
699             {
700                 final Collection<Object> elements = new ArrayList<Object>();
701                 for (final Iterator iterator = element.getChildElements(); iterator.hasNext();)
702                 {
703                     OMElement omElement = (OMElement)iterator.next();
704                     elements.add(deserialize(
705                             omElement,
706                             type.getComponentType(),
707                             typeMapper));
708                 }
709                 bean =
710                     elements.toArray((Object[])Array.newInstance(
711                             type.getComponentType(),
712                             0));
713             }
714             else
715             {
716                 try
717                 {
718                     type = getAppropriateType(element, type);
719                     bean = typeMapper.getObject(type);
720                     final java.beans.PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(type);
721                     for (int ctr = 0; ctr < descriptors.length; ctr++)
722                     {
723                         final java.beans.PropertyDescriptor descriptor = descriptors[ctr];
724                         final String name = descriptor.getName();
725                         if (!CLASS.equals(name))
726                         {
727                             final OMElement propertyElement = findElementByName(
728                                     element,
729                                     name);
730 
731                             if (propertyElement != null)
732                             {
733                                 PropertyUtils.setProperty(
734                                     bean,
735                                     name,
736                                     deserialize(
737                                         propertyElement,
738                                         descriptor.getPropertyType(),
739                                         typeMapper));
740                             }
741                         }
742                     }
743                 }
744                 catch (final Throwable throwable)
745                 {
746                     throw new RuntimeException(throwable);
747                 }
748             }
749         }
750         return bean;
751     }
752 
753     /**
754      * Gets the object given the type, element and typeMapper.
755      * @param type the type of object to get.
756      * @param element the elemtn that has the value to populate the object with.
757      * @param typeMapper the mapper used for retriving the value if it can't be found
758      *        by the simple type mapper.
759      * @return the object
760      */
761     private static Object getSimpleTypeObject(Class type,
762         OMElement element, TypeMapper typeMapper)
763     {
764         Object object = org.apache.axis2.databinding.typemapping.SimpleTypeMapper.getSimpleTypeObject(
765             type,
766             element);
767         if (object == null && element != null)
768         {
769             object = typeMapper.getObject(type, element.getText());
770         }
771         return object;
772     }
773 
774     /**
775      * The java package separator character.
776      */
777     private static final String PACKAGE_SEPARATOR = ".";
778 
779     /**
780      * The xsi:type Qname.
781      */
782     private static final QName XSI_TYPE_QNAME = new QName(XSI_NS, TYPE);
783 
784     /**
785      * Gets the appropriate type from checking the xsi:type (if present).  Currently
786      * this just assumes any types in a hierarchy are in the same package.
787      *
788      * @param element the element from which to retrieve the type.
789      * @param type the current type.
790      * @return the appropriate type.
791      * @throws ClassNotFoundException
792      */
793     private static Class getAppropriateType(final OMElement element, Class type) throws ClassNotFoundException
794     {
795         final String xsiTypeName = element.getAttributeValue(XSI_TYPE_QNAME);
796         if (xsiTypeName != null)
797         {
798             final String typeName = getLocalName(xsiTypeName);
799             if (!typeName.equals(type.getSimpleName()))
800             {
801                 // TODO: need to handle types that aren't in the same package (we should look up the
802                 // mapped class here instead of assuming the same package)
803                 type = Thread.currentThread().getContextClassLoader().loadClass(
804                     type.getPackage().getName() + PACKAGE_SEPARATOR + typeName);
805             }
806         }
807         return type;
808     }
809 
810     /**
811      * Strips the prefix from a type name in the given form: prefix:localName
812      * to get the local name.
813      *
814      * @param typeName the type name with an optional prefix
815      * @return the local name.
816      */
817     private static String getLocalName(final String typeName)
818     {
819         String localName;
820         String[] names = typeName.split(NS_SEPARATOR);
821         if (names.length > 1)
822         {
823             localName = names[1];
824         }
825         else
826         {
827             localName = names[0];
828         }
829         return localName;
830     }
831 
832     /**
833      * Finds an element having the given <code>name</code> from the child elements on the given
834      * <code>element</code>.
835      *
836      * @param element the element to search.
837      * @param name the name of the element to find.
838      * @return the found element or null if one couldn't be found.
839      */
840     private static OMElement findElementByName(
841         final OMElement element,
842         final String name)
843     {
844         OMElement found = null;
845         for (final Iterator iterator = element.getChildElements(); iterator.hasNext();)
846         {
847             final OMElement child = (OMElement)iterator.next();
848             if (child.getLocalName().equals(name))
849             {
850                 found = child;
851                 break;
852             }
853         }
854         return found;
855     }
856 
857     /**
858      * First delegate to the Axis2 simple type mapper, if that says
859      * its simple, it is, otherwise check to see if the type is an enumeration (typesafe
860      * or Java5 version).
861      *
862      * @param bean the bean to check.
863      * @return true/false
864      */
865     private static boolean isSimpleType(final Object bean, final TypeMapper typeMapper)
866     {
867         return typeMapper.isSimpleType(bean != null ? bean.getClass() : null);
868     }
869 }