1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 package org.exolab.castor.xml;
40
41 import java.io.IOException;
42 import java.io.PrintWriter;
43 import java.io.Writer;
44 import java.lang.reflect.Array;
45 import java.lang.reflect.Method;
46 import java.math.BigDecimal;
47 import java.util.ArrayList;
48 import java.util.Enumeration;
49 import java.util.HashSet;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Set;
53 import java.util.Stack;
54 import java.util.StringTokenizer;
55
56 import org.apache.commons.lang3.StringUtils;
57 import org.apache.commons.logging.Log;
58 import org.apache.commons.logging.LogFactory;
59 import org.castor.core.util.Base64Encoder;
60 import org.castor.core.util.HexDecoder;
61 import org.castor.core.util.Messages;
62 import org.castor.mapping.BindingType;
63 import org.castor.mapping.MappingUnmarshaller;
64 import org.castor.xml.InternalContext;
65 import org.castor.xml.XMLProperties;
66 import org.exolab.castor.mapping.ClassDescriptor;
67 import org.exolab.castor.mapping.CollectionHandler;
68 import org.exolab.castor.mapping.FieldHandler;
69 import org.exolab.castor.mapping.MapHandler;
70 import org.exolab.castor.mapping.MapItem;
71 import org.exolab.castor.mapping.Mapping;
72 import org.exolab.castor.mapping.MappingException;
73 import org.exolab.castor.mapping.MappingLoader;
74 import org.exolab.castor.mapping.handlers.MapHandlers;
75 import org.exolab.castor.mapping.loader.CollectionHandlers;
76 import org.exolab.castor.types.AnyNode;
77 import org.exolab.castor.util.SafeStack;
78 import org.exolab.castor.xml.descriptors.RootArrayDescriptor;
79 import org.exolab.castor.xml.descriptors.StringClassDescriptor;
80 import org.exolab.castor.xml.handlers.DateFieldHandler;
81 import org.exolab.castor.xml.handlers.EnumFieldHandler;
82 import org.exolab.castor.xml.util.AnyNode2SAX2;
83 import org.exolab.castor.xml.util.AttributeSetImpl;
84 import org.exolab.castor.xml.util.DocumentHandlerAdapter;
85 import org.exolab.castor.xml.util.SAX2DOMHandler;
86 import org.exolab.castor.xml.util.StaxEventHandler;
87 import org.exolab.castor.xml.util.StaxStreamHandler;
88 import org.exolab.castor.xml.util.XMLClassDescriptorAdapter;
89 import org.exolab.castor.xml.util.XMLClassDescriptorImpl;
90 import org.exolab.castor.xml.util.XMLFieldDescriptorImpl;
91 import org.w3c.dom.Node;
92 import org.xml.sax.ContentHandler;
93 import org.xml.sax.DocumentHandler;
94 import org.xml.sax.SAXException;
95 import org.xml.sax.helpers.AttributesImpl;
96
97 import javax.xml.stream.XMLEventWriter;
98 import javax.xml.stream.XMLStreamWriter;
99
100 import javax.xml.transform.Result;
101 import javax.xml.transform.dom.DOMResult;
102 import javax.xml.transform.sax.SAXResult;
103 import javax.xml.transform.stream.StreamResult;
104
105
106
107
108
109
110
111
112
113
114 public class Marshaller extends MarshalFramework {
115
116
117
118
119
120
121
122
123
124 private static final Log LOG = LogFactory.getLog(Marshaller.class);
125
126
127
128
129 private static final String CDATA = "CDATA";
130
131
132
133
134 private static final String DEFAULT_PREFIX = "ns";
135
136
137
138
139
140 private static final String SERIALIZER_NOT_SAX_CAPABLE = "conf.serializerNotSaxCapable";
141
142
143
144
145 private static final String XSI_PREFIX = "xsi";
146
147
148
149
150 private static final String XSI_TYPE = "xsi:type";
151
152
153
154
155 private int _namespaceCounter = 0;
156
157
158
159
160 private static final StringClassDescriptor STRING_CLASS_DESCRIPTOR = new StringClassDescriptor();
161
162
163
164
165
166
167
168
169 private boolean _asDocument = true;
170
171
172
173
174 private int _depth = 0;
175
176
177
178
179
180 private OutputFormat _format = null;
181
182
183
184
185 private ContentHandler _handler = null;
186
187
188
189
190 private boolean _marshalExtendedType = true;
191
192
193
194
195
196 private MarshalListener _marshalListener = null;
197
198
199
200
201 private NamespacesStack namespacesStack = new NamespacesStack();
202
203
204
205
206 private List<String> _packages = new ArrayList<String>();
207
208
209
210
211 private Stack _parents = new SafeStack();
212
213
214
215
216 private List<ProcessingInstruction> _processingInstructions =
217 new ArrayList<ProcessingInstruction>();
218
219
220
221
222 private String _rootElement = null;
223
224
225
226
227 private boolean _saveMapKeys = true;
228
229
230
231
232
233 private Serializer _serializer = null;
234
235
236
237
238 private boolean _suppressNamespaces = false;
239
240
241
242
243 private boolean _suppressXSIType = false;
244
245 private boolean _useXSITypeAtRoot = false;
246
247
248
249
250 private AttributeSetImpl _topLevelAtts = new AttributeSetImpl();
251
252
253
254
255
256 private AttributesImpl _attributes = new AttributesImpl();
257
258
259
260
261 private boolean _validate = false;
262
263
264
265
266
267 private final Set<String> _proxyInterfaces = new HashSet<String>();
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283 public Marshaller(final DocumentHandler handler) {
284 super(null);
285 checkNotNull(handler, "The given 'org.sax.DocumentHandler' instance is null.");
286
287 setContentHandler(new DocumentHandlerAdapter(handler));
288 }
289
290
291
292
293
294
295
296
297 public void setDocumentHandler(final DocumentHandler handler) {
298 checkNotNull(handler, "The given 'org.sax.DocumentHandler' instance is null.");
299
300 setContentHandler(new DocumentHandlerAdapter(handler));
301 }
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316 public Marshaller(final ContentHandler contentHandler) {
317 super(null);
318 checkNotNull(contentHandler, "The given 'org.sax.ContentHandler' is null.");
319
320 setContentHandler(contentHandler);
321 }
322
323
324
325
326
327
328
329
330
331 public Marshaller(final InternalContext internalContext) {
332 super(internalContext);
333 }
334
335
336
337
338 public Marshaller() {
339 super(null);
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356 public Marshaller(final Writer out) throws IOException {
357 super(null);
358 setWriter(out);
359 }
360
361
362
363
364
365
366
367
368
369
370
371
372 public Marshaller(XMLStreamWriter xmlStreamWriter) {
373 super(null);
374 setXmlStreamWriter(xmlStreamWriter);
375 }
376
377
378
379
380
381
382
383
384
385
386
387
388 public Marshaller(XMLEventWriter xmlEventWriter) {
389 super(null);
390 setXmlEventWriter(xmlEventWriter);
391 }
392
393
394
395
396
397
398
399
400
401 public void setWriter(final Writer out) throws IOException {
402 checkNotNull(out, "The given 'java.io.Writer' instance is null.");
403
404 configureSerializer(out);
405 }
406
407
408
409
410
411
412
413
414
415
416
417 public void setResult(Result result) throws IOException {
418 checkNotNull(result, "The given 'javax.xml.transform.Result' instance is null.");
419
420 if (result instanceof DOMResult) {
421 DOMResult domResult = (DOMResult) result;
422
423 if (domResult.getNode() != null) {
424
425 setNode(domResult.getNode());
426 return;
427 }
428 } else if (result instanceof SAXResult) {
429 SAXResult saxResult = (SAXResult) result;
430
431 if (saxResult.getHandler() != null) {
432
433 setContentHandler(saxResult.getHandler());
434 return;
435
436 }
437 } else if (result instanceof StreamResult) {
438 StreamResult streamResult = (StreamResult) result;
439
440 if (streamResult.getWriter() != null) {
441
442 setWriter(streamResult.getWriter());
443 return;
444 } else if (streamResult.getOutputStream() != null) {
445
446 setWriter(new PrintWriter(streamResult.getOutputStream()));
447 return;
448 }
449 }
450
451 throw new IllegalArgumentException(
452 "The given 'javax.transofrm.xml.Result' is not supported, or were incorrectly instantiated.");
453 }
454
455
456 private void configureSerializer(Writer out) throws IOException {
457 _serializer = getInternalContext().getSerializer();
458
459 if (_serializer == null)
460 throw new RuntimeException("Unable to obtain serializer");
461
462 _serializer.setOutputCharStream(out);
463
464
465
466
467 _handler = new DocumentHandlerAdapter(_serializer.asDocumentHandler());
468
469 if (_handler == null) {
470 String err = Messages.format(SERIALIZER_NOT_SAX_CAPABLE, _serializer.getClass().getName());
471 throw new RuntimeException(err);
472 }
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489 public Marshaller(final Node node) {
490 super(null);
491 checkNotNull(node, "The given 'org.w3c.dom.Node' instance is null.");
492
493 setContentHandler(new DocumentHandlerAdapter(new SAX2DOMHandler(node)));
494 }
495
496
497
498
499
500
501
502
503 public void setNode(final Node node) {
504 checkNotNull(node, "The given 'org.w3c.dom.Node' instance is null.");
505
506 setContentHandler(new DocumentHandlerAdapter(new SAX2DOMHandler(node)));
507 }
508
509
510
511
512
513
514
515
516
517
518 public void setXmlStreamWriter(XMLStreamWriter xmlStreamWriter) {
519 checkNotNull(xmlStreamWriter, "The given 'java.xml.stream.XMLStreamWriter' instance is null.");
520
521 setContentHandler(new StaxStreamHandler(xmlStreamWriter));
522 }
523
524
525
526
527
528
529
530
531
532
533 public void setXmlEventWriter(XMLEventWriter xmlEventWriter) {
534 checkNotNull(xmlEventWriter, "The given 'java.xml.stream.XMLEventWriter' instance is null.");
535
536 setContentHandler(new StaxEventHandler(xmlEventWriter));
537 }
538
539
540
541
542
543
544
545 public void setInternalContext(final InternalContext internalContext) {
546 super.setInternalContext(internalContext);
547 deriveProperties();
548 }
549
550
551
552
553
554
555
556
557 private void deriveProperties() {
558 _validate = getInternalContext().marshallingValidation();
559 _saveMapKeys =
560 getInternalContext().getBooleanProperty(XMLProperties.SAVE_MAP_KEYS).booleanValue();
561
562 String prop = getInternalContext().getStringProperty(XMLProperties.PROXY_INTERFACES);
563 if (prop != null) {
564 StringTokenizer tokenizer = new StringTokenizer(prop, ", ");
565 while (tokenizer.hasMoreTokens()) {
566 _proxyInterfaces.add(tokenizer.nextToken());
567 }
568 }
569 }
570
571
572
573
574
575
576
577
578
579
580 public void addProcessingInstruction(String target, String data) {
581
582 checkNotEmpty(target, "The argument 'target' must not be null or empty.");
583 checkNotNull(data, "The argument 'data' must not be null.");
584
585 _processingInstructions.add(new ProcessingInstruction(target, data));
586 }
587
588
589
590
591
592
593
594
595 public void setDoctype(String publicId, String systemId) {
596
597 if (_serializer != null) {
598 if (_format == null) {
599 _format = getInternalContext().getOutputFormat();
600 }
601 _format.setDoctype(publicId, systemId);
602
603
604 _serializer.setOutputFormat(_format);
605
606 setDocumentHandler();
607 } else {
608 String error = "doctype cannot be set if you've passed in " + "your own DocumentHandler";
609 throw new IllegalStateException(error);
610 }
611 }
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627 public void setSupressXMLDeclaration(boolean supressXMLDeclaration) {
628 setMarshalAsDocument(!supressXMLDeclaration);
629 }
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644 public void setMarshalAsDocument(boolean asDocument) {
645
646 _asDocument = asDocument;
647
648 if (_serializer != null) {
649
650 if (_format == null) {
651 _format = getInternalContext().getOutputFormat();
652 }
653 _format.setOmitXMLDeclaration(!asDocument);
654 _format.setOmitDocumentType(!asDocument);
655
656
657
658 _serializer.setOutputFormat(_format);
659
660 setDocumentHandler();
661 }
662
663 }
664
665
666
667
668
669
670
671
672 public void setMapping(final Mapping mapping) throws MappingException {
673
674
675
676
677 if ((getInternalContext() == null)
678 || (getInternalContext().getXMLClassDescriptorResolver() == null)) {
679 String message = "No internal context or no class descriptor in context.";
680 LOG.warn(message);
681 throw new IllegalStateException(message);
682 }
683
684 MappingUnmarshaller mum = new MappingUnmarshaller();
685 MappingLoader resolver = mum.getMappingLoader(mapping, BindingType.XML);
686 getInternalContext().getXMLClassDescriptorResolver().setMappingLoader(resolver);
687 }
688
689
690
691
692
693
694
695
696
697
698
699 public void setMarshalListener(MarshalListener listener) {
700 _marshalListener = listener;
701 }
702
703
704
705
706
707
708
709
710
711 public void setNamespaceMapping(final String nsPrefix, final String nsURI) {
712 checkNotEmpty(nsURI, "Namespace URI must be not null.");
713 namespacesStack.addNamespace(nsPrefix, nsURI);
714 }
715
716
717
718
719
720
721 public void setRootElement(final String rootElement) {
722 _rootElement = rootElement;
723 }
724
725
726
727
728
729
730 public String getRootElement() {
731 return _rootElement;
732 }
733
734
735
736
737
738
739
740 public void setNSPrefixAtRoot(boolean nsPrefixAtRoot) {
741
742
743 }
744
745
746
747
748
749
750
751 public boolean getNSPrefixAtRoot() {
752 return true;
753 }
754
755
756
757
758
759
760
761 public XMLClassDescriptorResolver getResolver() {
762
763
764
765
766
767 if ((getInternalContext() == null)
768 || (getInternalContext().getXMLClassDescriptorResolver() == null)) {
769 String message = "No internal context or no class descriptor in context.";
770 LOG.warn(message);
771 throw new IllegalStateException(message);
772 }
773 return getInternalContext().getXMLClassDescriptorResolver();
774
775 }
776
777
778
779
780
781
782
783
784
785
786
787 public void setResolver(final XMLClassDescriptorResolver cdr) {
788
789 if (cdr != null) {
790 getInternalContext().setXMLClassDescriptorResolver(cdr);
791
792 }
793
794 }
795
796
797
798
799
800
801
802
803
804
805 public void setValidation(boolean validate) {
806 _validate = validate;
807 }
808
809 public boolean getValidation() {
810 return _validate;
811 }
812
813
814
815
816
817 public void setMarshalExtendedType(boolean marshalExtendedType) {
818 _marshalExtendedType = marshalExtendedType;
819 }
820
821
822
823
824
825
826
827
828
829 public boolean getMarshalExtendedType() {
830 return _marshalExtendedType;
831 }
832
833
834
835
836
837
838
839
840
841 public static void marshal(Object object, Writer out)
842 throws MarshalException, ValidationException {
843 try {
844 staticMarshal(object, new Marshaller(out));
845 } catch (IOException e) {
846 throw new MarshalException(e);
847 }
848 }
849
850
851
852
853
854
855
856
857
858 public static void marshal(Object object, DocumentHandler handler)
859 throws MarshalException, ValidationException {
860 staticMarshal(object, new Marshaller(handler));
861 }
862
863
864
865
866
867
868
869
870
871 public static void marshal(Object object, ContentHandler handler)
872 throws MarshalException, ValidationException {
873 staticMarshal(object, new Marshaller(handler));
874 }
875
876
877
878
879
880
881
882
883
884 public static void marshal(Object object, Node node)
885 throws MarshalException, ValidationException {
886 staticMarshal(object, new Marshaller(node));
887 }
888
889
890
891
892
893
894
895
896
897 private static void staticMarshal(final Object object, final Marshaller marshaller)
898 throws MarshalException, ValidationException {
899 if (object == null) {
900 throw new MarshalException("object must not be null");
901 }
902
903 if (LOG.isInfoEnabled()) {
904 LOG.info("Marshaller called using one of the *static* "
905 + " marshal(Object, *) methods. This will ignore any "
906 + " mapping files as specified. Please consider switching to "
907 + " using Marshaller instances and calling one of the" + " marshal(*) methods.");
908 }
909
910 marshaller.marshal(object);
911 }
912
913
914
915
916
917
918
919
920 public void marshal(Object object) throws MarshalException, ValidationException {
921 if (object == null)
922 throw new MarshalException("object must not be null");
923
924 if (LOG.isDebugEnabled()) {
925 LOG.debug("Marshalling " + object.getClass().getName());
926 }
927
928 if (object instanceof AnyNode) {
929 try {
930 AnyNode2SAX2.fireEvents((AnyNode) object, _handler, namespacesStack);
931 } catch (SAXException e) {
932 throw new MarshalException(e);
933 }
934 } else {
935 validate(object);
936 MarshalState mstate = new MarshalState(object, "root");
937 if (_asDocument) {
938 try {
939 _handler.startDocument();
940
941 for (int i = 0; i < _processingInstructions.size(); i++) {
942 ProcessingInstruction pi = _processingInstructions.get(i);
943 _handler.processingInstruction(pi.getTarget(), pi.getData());
944 }
945 marshal(object, null, _handler, mstate);
946 _handler.endDocument();
947 } catch (SAXException sx) {
948 throw new MarshalException(sx);
949 }
950 } else {
951 marshal(object, null, _handler, mstate);
952 }
953 }
954
955 }
956
957
958
959
960
961
962
963
964
965
966
967
968 private void marshal(Object object, XMLFieldDescriptor descriptor, ContentHandler handler,
969 final MarshalState mstate) throws MarshalException, ValidationException {
970
971
972 if (object == null) {
973 String err = "Marshaller#marshal: null parameter: 'object'";
974 throw new MarshalException(err);
975 }
976
977 if (descriptor != null && descriptor.isTransient())
978 return;
979
980
981 if (_marshalListener != null) {
982 boolean toBeMarshalled = true;
983 try {
984 toBeMarshalled = _marshalListener.preMarshal(object);
985 } catch (RuntimeException e) {
986 LOG.error(
987 "Invoking #preMarshal() on your custom MarshalListener instance caused the following problem:",
988 e);
989 }
990 if (!toBeMarshalled) {
991 return;
992 }
993 }
994
995
996 if (object instanceof AnyNode) {
997 try {
998 AnyNode2SAX2.fireEvents((AnyNode) object, handler, namespacesStack);
999 } catch (SAXException e) {
1000 throw new MarshalException(e);
1001 }
1002 return;
1003 }
1004
1005 boolean containerField = false;
1006
1007 if (descriptor != null && descriptor.isContainer()) {
1008 containerField = true;
1009 }
1010
1011
1012
1013 if (_parents.search(object) >= 0) {
1014 return;
1015 }
1016
1017 _parents.push(object);
1018
1019 final boolean isNil = (object instanceof NilObject);
1020
1021 Class<?> cls = null;
1022
1023 if (!isNil) {
1024 cls = object.getClass();
1025
1026 if (!_proxyInterfaces.isEmpty()) {
1027 boolean isProxy = false;
1028
1029 Class<?>[] interfaces = cls.getInterfaces();
1030 for (int i = 0; i < interfaces.length; i++) {
1031 if (_proxyInterfaces.contains(interfaces[i].getName())) {
1032 isProxy = true;
1033 }
1034 }
1035
1036 if (isProxy) {
1037 cls = cls.getSuperclass();
1038 }
1039 }
1040 } else {
1041 cls = ((NilObject) object).getClassDescriptor().getJavaClass();
1042 }
1043
1044 boolean byteArray = false;
1045 if (cls.isArray())
1046 byteArray = (cls.getComponentType() == Byte.TYPE);
1047
1048 boolean atRoot = false;
1049 if (descriptor == null) {
1050 descriptor = new XMLFieldDescriptorImpl(cls, "root", null, null);
1051 atRoot = true;
1052 }
1053
1054
1055
1056 String name = descriptor.getXMLName();
1057 if (atRoot && _rootElement != null)
1058 name = _rootElement;
1059
1060 boolean autoNameByClass = false;
1061 if (name == null) {
1062 autoNameByClass = true;
1063 name = cls.getName();
1064
1065 int idx = name.lastIndexOf('.');
1066 if (idx >= 0) {
1067 name = name.substring(idx + 1);
1068 }
1069
1070 name = getInternalContext().getXMLNaming().toXMLName(name);
1071 }
1072
1073
1074 XMLClassDescriptor classDesc = null;
1075 boolean saveType = false;
1076
1077 if (object instanceof NilObject) {
1078 classDesc = ((NilObject) object).getClassDescriptor();
1079 } else if (cls == descriptor.getFieldType()) {
1080 classDesc = (XMLClassDescriptor) descriptor.getClassDescriptor();
1081 }
1082
1083 if (classDesc == null) {
1084
1085
1086
1087
1088
1089 if (isPrimitive(cls) || byteArray) {
1090 classDesc = STRING_CLASS_DESCRIPTOR;
1091
1092
1093 Class<?> fieldType = descriptor.getFieldType();
1094 if (cls != fieldType) {
1095 while (fieldType.isArray()) {
1096 fieldType = fieldType.getComponentType();
1097 }
1098 saveType = (!primitiveOrWrapperEquals(cls, fieldType));
1099 }
1100 } else {
1101 saveType = cls.isArray();
1102
1103
1104 String className = cls.getName();
1105 int idx = className.lastIndexOf(".");
1106 String pkgName = null;
1107 if (idx > 0) {
1108 pkgName = className.substring(0, idx + 1);
1109 if (!_packages.contains(pkgName))
1110 _packages.add(pkgName);
1111 }
1112
1113 if (_marshalExtendedType) {
1114
1115
1116
1117
1118 if ((cls != descriptor.getFieldType()) || atRoot) {
1119
1120 saveType = true;
1121
1122 boolean containsDesc = false;
1123
1124
1125
1126
1127
1128 if (!atRoot) {
1129 String nsURI = descriptor.getNameSpaceURI();
1130 XMLClassDescriptor tmpDesc = null;
1131 try {
1132 tmpDesc = getResolver().resolveByXMLName(name, nsURI, null);
1133 } catch (ResolverException rx) {
1134
1135
1136
1137 if (LOG.isDebugEnabled()) {
1138 LOG.debug("Error resolving", rx);
1139 }
1140 }
1141
1142 if (tmpDesc != null) {
1143 Class<?> tmpType = tmpDesc.getJavaClass();
1144 if (tmpType == cls) {
1145 containsDesc = (!tmpType.isInterface());
1146 }
1147 }
1148 }
1149
1150 if (!containsDesc) {
1151
1152
1153
1154
1155 if (atRoot) {
1156 if (_useXSITypeAtRoot) {
1157 XMLMappingLoader ml = (XMLMappingLoader) getResolver().getMappingLoader();
1158 if (ml != null) {
1159 containsDesc = (ml.getDescriptor(cls.getName()) != null);
1160 }
1161 } else {
1162
1163
1164 containsDesc = true;
1165 }
1166
1167 }
1168
1169
1170
1171 if ((!containsDesc) && (pkgName == null)) {
1172
1173
1174 classDesc = getClassDescriptor(cls);
1175 if (classDesc != null) {
1176 String tmpName = classDesc.getXMLName();
1177 if (name.equals(tmpName))
1178 saveType = false;
1179 }
1180 }
1181 }
1182
1183 if (containsDesc)
1184 saveType = false;
1185
1186 }
1187
1188
1189 if (classDesc == null)
1190 classDesc = getClassDescriptor(cls);
1191
1192 }
1193 else {
1194
1195 cls = descriptor.getFieldType();
1196 classDesc = getClassDescriptor(cls);
1197 }
1198
1199
1200
1201
1202
1203 if ((classDesc == null) && cls.isArray()) {
1204 classDesc = new RootArrayDescriptor(cls);
1205 if (atRoot) {
1206 containerField = (!_asDocument);
1207 }
1208 }
1209 }
1210
1211 if (classDesc == null) {
1212
1213 if ((cls == Void.class) || (cls == Object.class) || (cls == Class.class)) {
1214
1215 throw new MarshalException(MarshalException.BASE_CLASS_OR_VOID_ERR);
1216 }
1217 _parents.pop();
1218 return;
1219 }
1220 }
1221
1222
1223 if (autoNameByClass) {
1224 if (classDesc.getXMLName() != null) {
1225 name = classDesc.getXMLName();
1226 }
1227 }
1228
1229
1230
1231 if (atRoot) {
1232 mstate._xmlName = name;
1233 }
1234
1235
1236
1237
1238
1239
1240
1241 saveType = (saveType && (!_suppressXSIType));
1242
1243
1244 if (saveType) {
1245
1246 if (descriptor.getHandler() instanceof DateFieldHandler)
1247 saveType = false;
1248 else if (descriptor.getHandler() instanceof EnumFieldHandler)
1249 saveType = false;
1250 else if (isNil)
1251 saveType = false;
1252 }
1253
1254
1255
1256 if (saveType) {
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275 String xmlElementName = name;
1276 String xmlNamespace = descriptor.getNameSpaceURI();
1277
1278
1279
1280 XMLClassDescriptor xmlElementNameClassDesc = null;
1281 try {
1282 xmlElementNameClassDesc = getResolver().resolveByXMLName(xmlElementName, null, null);
1283 } catch (ResolverException rx) {
1284
1285
1286
1287 if (LOG.isDebugEnabled()) {
1288 LOG.debug("Error resolving " + xmlElementName, rx);
1289 }
1290 }
1291
1292
1293 if ((xmlElementName != null) && (xmlElementNameClassDesc != null)) {
1294
1295 try {
1296 Iterator<ClassDescriptor> classDescriptorIter =
1297 getResolver().resolveAllByXMLName(xmlElementName, null, null);
1298 for (; classDescriptorIter.hasNext();) {
1299 xmlElementNameClassDesc = (XMLClassDescriptor) classDescriptorIter.next();
1300 if (cls == xmlElementNameClassDesc.getJavaClass()) {
1301 break;
1302 }
1303
1304 xmlElementNameClassDesc = null;
1305 }
1306 } catch (ResolverException rx) {
1307 if (LOG.isDebugEnabled()) {
1308 LOG.debug("Error resolving " + xmlElementName, rx);
1309 }
1310 xmlElementNameClassDesc = null;
1311 }
1312
1313
1314
1315 if (xmlElementNameClassDesc instanceof XMLClassDescriptorAdapter) {
1316
1317
1318 XMLClassDescriptor tempContaining =
1319 (XMLClassDescriptor) descriptor.getContainingClassDescriptor();
1320
1321
1322
1323
1324 if (tempContaining != null) {
1325 XMLFieldDescriptor fieldDescMatch =
1326 tempContaining.getFieldDescriptor(xmlElementName, xmlNamespace, NodeType.Element);
1327
1328
1329 InheritanceMatch[] matches = searchInheritance(xmlElementName, null, tempContaining);
1330
1331
1332
1333 if (matches.length == 1) {
1334
1335 boolean foundTheRightClass = ((xmlElementNameClassDesc != null)
1336 && (cls == xmlElementNameClassDesc.getJavaClass()));
1337
1338 boolean oneAndOnlyOneMatchedField =
1339 ((fieldDescMatch != null) || (matches[0].parentFieldDesc == descriptor));
1340
1341
1342 if (foundTheRightClass && oneAndOnlyOneMatchedField) {
1343 saveType = false;
1344
1345 }
1346 }
1347 }
1348 }
1349 }
1350 }
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362 if (!atRoot) {
1363 namespacesStack.addNewNamespaceScope();
1364 }
1365
1366 String nsPrefix = "";
1367 String nsURI = "";
1368
1369 if (!_suppressNamespaces) {
1370
1371
1372
1373
1374 nsPrefix = descriptor.getNameSpacePrefix();
1375 if (nsPrefix == null)
1376 nsPrefix = classDesc.getNameSpacePrefix();
1377
1378 nsURI = descriptor.getNameSpaceURI();
1379 if (nsURI == null)
1380 nsURI = classDesc.getNameSpaceURI();
1381
1382 if ((nsURI == null) && (nsPrefix != null)) {
1383 nsURI = namespacesStack.getNamespaceURI(nsPrefix);
1384 } else if ((nsPrefix == null) && (nsURI != null)) {
1385 nsPrefix = namespacesStack.getNamespacePrefix(nsURI);
1386 }
1387
1388 if (nsURI != null) {
1389 String defaultNamespace = namespacesStack.getDefaultNamespaceURI();
1390 if ((nsPrefix == null) && (!nsURI.equals(defaultNamespace))) {
1391 if ((defaultNamespace == null) && atRoot) {
1392 nsPrefix = "";
1393 } else
1394 nsPrefix = DEFAULT_PREFIX + (++_namespaceCounter);
1395 }
1396 declareNamespace(nsPrefix, nsURI);
1397 } else {
1398 nsURI = "";
1399
1400 String defaultNamespace = namespacesStack.getNamespaceURI("");
1401 if ((defaultNamespace != null) && (!"".equals(defaultNamespace)))
1402 namespacesStack.addNamespace("", "");
1403 }
1404 }
1405
1406
1407
1408
1409
1410
1411
1412 AttributesImpl atts = new AttributesImpl();
1413
1414
1415 if (atRoot) {
1416
1417 if (_topLevelAtts.getSize() > 0) {
1418 namespacesStack.addNamespace(XSI_PREFIX, XSI_NAMESPACE);
1419 }
1420
1421 for (int i = 0; i < _topLevelAtts.getSize(); i++) {
1422 String localName = _topLevelAtts.getName(i);
1423 String qName = localName;
1424 String ns = "";
1425 if (!_suppressNamespaces) {
1426 ns = _topLevelAtts.getNamespace(i);
1427 String prefix = null;
1428 if (StringUtils.isNotEmpty(ns)) {
1429 prefix = namespacesStack.getNonDefaultNamespacePrefix(ns);
1430 }
1431 if (StringUtils.isNotEmpty(prefix)) {
1432 qName = prefix + ':' + qName;
1433 }
1434 if (ns == null)
1435 ns = "";
1436 }
1437 atts.addAttribute(ns, localName, qName, CDATA, _topLevelAtts.getValue(i));
1438 }
1439 }
1440
1441
1442
1443
1444
1445 int nestedAttCount = 0;
1446 XMLFieldDescriptor[] nestedAtts = null;
1447 XMLFieldDescriptor[] descriptors = null;
1448 if ((!descriptor.isReference()) && (!isNil)) {
1449 descriptors = classDesc.getAttributeDescriptors();
1450 } else {
1451
1452 descriptors = NO_FIELD_DESCRIPTORS;
1453 }
1454
1455 for (int i = 0; i < descriptors.length; i++) {
1456 XMLFieldDescriptor attributeDescriptor = descriptors[i];
1457 if (attributeDescriptor == null) {
1458 continue;
1459 }
1460 String path = attributeDescriptor.getLocationPath();
1461 if (StringUtils.isNotEmpty(path)) {
1462
1463 if (nestedAtts == null) {
1464 nestedAtts = new XMLFieldDescriptor[descriptors.length - i];
1465 }
1466 nestedAtts[nestedAttCount] = attributeDescriptor;
1467 nestedAttCount++;
1468 } else {
1469 processAttribute(object, attributeDescriptor, atts);
1470 }
1471 }
1472
1473
1474 if (mstate._nestedAttCount > 0) {
1475 for (int i = 0; i < mstate._nestedAtts.length; i++) {
1476 XMLFieldDescriptor attributeDescriptor = mstate._nestedAtts[i];
1477 if (attributeDescriptor == null) {
1478 continue;
1479 }
1480 String locationPath = attributeDescriptor.getLocationPath();
1481 if (name.equals(locationPath)) {
1482
1483 mstate._nestedAtts[i] = null;
1484
1485 mstate._nestedAttCount--;
1486 processAttribute(mstate.getOwner(), attributeDescriptor, atts);
1487 }
1488 }
1489 }
1490
1491
1492
1493 if (!isNil)
1494 processContainerAttributes(object, classDesc, atts);
1495
1496
1497 String attValue = descriptor.getXMLProperty(XMLFieldDescriptor.PROPERTY_XML_SPACE);
1498 if (attValue != null) {
1499 atts.addAttribute(Namespaces.XML_NAMESPACE, SPACE_ATTR, XML_SPACE_ATTR, CDATA, attValue);
1500 }
1501
1502
1503 attValue = descriptor.getXMLProperty(XMLFieldDescriptor.PROPERTY_XML_LANG);
1504 if (attValue != null) {
1505 atts.addAttribute(Namespaces.XML_NAMESPACE, LANG_ATTR, XML_LANG_ATTR, CDATA, attValue);
1506 }
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516 if (saveType) {
1517
1518 declareNamespace(XSI_PREFIX, XSI_NAMESPACE);
1519
1520
1521
1522
1523
1524 String typeName = classDesc.getXMLName();
1525
1526
1527 boolean introspected = false;
1528 if (classDesc instanceof InternalXMLClassDescriptor)
1529 introspected = ((InternalXMLClassDescriptor) classDesc).introspected();
1530 else
1531 introspected = Introspector.introspected(classDesc);
1532
1533 boolean useJavaPrefix = false;
1534 if ((typeName == null) || introspected) {
1535 typeName = JAVA_PREFIX + cls.getName();
1536 useJavaPrefix = true;
1537 } else if (classDesc instanceof RootArrayDescriptor) {
1538 typeName = JAVA_PREFIX + cls.getName();
1539 useJavaPrefix = true;
1540 } else {
1541 String dcn = classDesc.getClass().getName();
1542 if (dcn.equals(XMLClassDescriptorImpl.class.getName())) {
1543 typeName = JAVA_PREFIX + cls.getName();
1544 useJavaPrefix = true;
1545 } else {
1546
1547 String tns = classDesc.getNameSpaceURI();
1548 String prefix = null;
1549 if (StringUtils.isNotEmpty(tns)) {
1550 prefix = namespacesStack.getNamespacePrefix(tns);
1551 if (StringUtils.isNotEmpty(prefix)) {
1552 typeName = prefix + ':' + typeName;
1553 }
1554 }
1555 }
1556 }
1557
1558 atts.addAttribute(XSI_NAMESPACE, TYPE_ATTR, XSI_TYPE, CDATA, typeName);
1559 if (useJavaPrefix) {
1560 if (namespacesStack.getNamespaceURI("java") == null) {
1561
1562 declareNamespace("java", "http://java.sun.com");
1563 }
1564 }
1565 }
1566
1567 if (isNil && !_suppressXSIType) {
1568
1569 declareNamespace(XSI_PREFIX, XSI_NAMESPACE);
1570
1571 atts.addAttribute(XSI_NAMESPACE, NIL_ATTR, XSI_NIL_ATTR, CDATA, TRUE_VALUE);
1572 }
1573
1574
1575
1576
1577
1578 String valueType = descriptor.getSchemaType();
1579 if ((valueType != null) && (valueType.equals(QNAME_NAME))) {
1580 object = resolveQName(object, descriptor);
1581 }
1582
1583
1584 String qName = null;
1585 if (nsPrefix != null) {
1586 int len = nsPrefix.length();
1587 if (len > 0) {
1588 qName = nsPrefix + ':' + name;
1589 } else
1590 qName = name;
1591 } else
1592 qName = name;
1593
1594
1595 Object firstNonNullValue = null;
1596 int firstNonNullIdx = 0;
1597
1598 try {
1599
1600
1601 if (!containerField) {
1602
1603
1604
1605 if ((!isNil) && descriptor.isNillable()) {
1606 XMLFieldDescriptor desc = classDesc.getContentDescriptor();
1607 descriptors = classDesc.getElementDescriptors();
1608 int descCount = descriptors.length;
1609 boolean isNilContent = (descCount > 0) || (desc != null);
1610
1611
1612 if (desc != null) {
1613 Object value = desc.getHandler().getValue(object);
1614 if (value != null) {
1615 isNilContent = false;
1616 descCount = 0;
1617 } else if (desc.isNillable() && desc.isRequired()) {
1618 isNilContent = false;
1619 descCount = 0;
1620 }
1621 }
1622
1623
1624 for (int i = 0; i < descCount; i++) {
1625 desc = descriptors[i];
1626 if (desc == null)
1627 continue;
1628 Object value = desc.getHandler().getValue(object);
1629 if (value != null) {
1630 isNilContent = false;
1631 firstNonNullIdx = i;
1632 firstNonNullValue = value;
1633 break;
1634 } else if (desc.isNillable() && desc.isRequired()) {
1635 isNilContent = false;
1636 firstNonNullIdx = i;
1637 firstNonNullValue = new NilObject(classDesc, desc);
1638 break;
1639 }
1640 }
1641
1642 if (isNilContent) {
1643 declareNamespace(XSI_PREFIX, XSI_NAMESPACE);
1644 atts.addAttribute(XSI_NAMESPACE, NIL_ATTR, XSI_NIL_ATTR, CDATA, TRUE_VALUE);
1645 }
1646 }
1647
1648
1649 namespacesStack.getCurrentNamespaceScope().sendStartEvents(handler);
1650
1651 if (qName == null) {
1652
1653
1654 String err = "Error in deriving name for type: " + cls.getName()
1655 + ", please report bug to: " + "http://castor.exolab.org.";
1656 throw new IllegalStateException(err);
1657 }
1658
1659
1660 handler.startElement(nsURI, name, qName, atts);
1661 }
1662 } catch (org.xml.sax.SAXException sx) {
1663 throw new MarshalException(sx);
1664 }
1665
1666
1667
1668
1669
1670
1671
1672 Stack<WrapperInfo> wrappers = null;
1673
1674
1675
1676
1677
1678
1679 if (!isNil) {
1680
1681 XMLFieldDescriptor cdesc = null;
1682 if (!descriptor.isReference()) {
1683 cdesc = classDesc.getContentDescriptor();
1684 }
1685 if (cdesc != null) {
1686 Object obj = null;
1687 try {
1688 obj = cdesc.getHandler().getValue(object);
1689 } catch (IllegalStateException ise) {
1690 LOG.warn("Error getting value from: " + object, ise);
1691 }
1692
1693 if (obj != null) {
1694
1695
1696
1697 String path = cdesc.getLocationPath();
1698 String currentLoc = null;
1699
1700 if (path != null) {
1701 _attributes.clear();
1702 if (wrappers == null) {
1703 wrappers = new SafeStack<WrapperInfo>();
1704 }
1705 try {
1706 while (path != null) {
1707
1708 String elemName = null;
1709 int idx = path.indexOf('/');
1710
1711 if (idx > 0) {
1712 elemName = path.substring(0, idx);
1713 path = path.substring(idx + 1);
1714 } else {
1715 elemName = path;
1716 path = null;
1717 }
1718
1719
1720
1721 if (currentLoc == null)
1722 currentLoc = elemName;
1723 else
1724 currentLoc = currentLoc + "/" + elemName;
1725
1726 String elemQName = elemName;
1727 if (StringUtils.isNotEmpty(nsPrefix)) {
1728 elemQName = nsPrefix + ':' + elemName;
1729 }
1730 wrappers.push(new WrapperInfo(elemName, elemQName, currentLoc));
1731
1732
1733 _attributes.clear();
1734 if (nestedAttCount > 0) {
1735 for (int na = 0; na < nestedAtts.length; na++) {
1736 if (nestedAtts[na] == null)
1737 continue;
1738 String tmpPath = nestedAtts[na].getLocationPath();
1739 if (tmpPath.equals(currentLoc)) {
1740 processAttribute(object, nestedAtts[na], _attributes);
1741 nestedAtts[na] = null;
1742 --nestedAttCount;
1743 }
1744 }
1745 }
1746 handler.startElement(nsURI, elemName, elemQName, _attributes);
1747 }
1748 } catch (SAXException sx) {
1749 throw new MarshalException(sx);
1750 }
1751 }
1752
1753
1754 char[] chars = null;
1755 Class<?> objType = obj.getClass();
1756 if (objType.isArray() && (objType.getComponentType() == Byte.TYPE)) {
1757
1758 final String schemaType = descriptor.getSchemaType();
1759 if (HexDecoder.DATA_TYPE.equals(schemaType)) {
1760 chars = new String(HexDecoder.encode((byte[]) obj)).toCharArray();
1761 } else {
1762 chars = Base64Encoder.encode((byte[]) obj);
1763 }
1764 } else {
1765
1766 String str = obj.toString();
1767 if (StringUtils.isNotEmpty(str)) {
1768 chars = str.toCharArray();
1769 }
1770 }
1771 if ((chars != null) && (chars.length > 0)) {
1772 try {
1773 handler.characters(chars, 0, chars.length);
1774 } catch (org.xml.sax.SAXException sx) {
1775 throw new MarshalException(sx);
1776 }
1777 }
1778 }
1779 }
1780
1781 else if (descriptor.isReference()) {
1782 Object id = getObjectID(object);
1783 if (id != null) {
1784 char[] chars = id.toString().toCharArray();
1785 try {
1786 handler.characters(chars, 0, chars.length);
1787 } catch (org.xml.sax.SAXException sx) {
1788 throw new MarshalException(sx);
1789 }
1790 }
1791 }
1792
1793 else if (byteArray) {
1794
1795 String schemaType = descriptor.getSchemaType();
1796 String componentType = descriptor.getComponentType();
1797 char[] chars = new char[0];
1798 if ((descriptor.isMultivalued() && HexDecoder.DATA_TYPE.equals(componentType))
1799 || HexDecoder.DATA_TYPE.equals(schemaType)) {
1800 chars = new String(HexDecoder.encode((byte[]) object)).toCharArray();
1801 } else {
1802 chars = Base64Encoder.encode((byte[]) object);
1803 }
1804 try {
1805 handler.characters(chars, 0, chars.length);
1806 } catch (org.xml.sax.SAXException sx) {
1807 throw new MarshalException(sx);
1808 }
1809 }
1810
1811 else if (isPrimitive(cls)) {
1812
1813 char[] chars;
1814 if (cls == java.math.BigDecimal.class) {
1815 chars = convertBigDecimalToString(object).toCharArray();
1816 } else {
1817 chars = object.toString().toCharArray();
1818 }
1819 try {
1820 handler.characters(chars, 0, chars.length);
1821 } catch (org.xml.sax.SAXException sx) {
1822 throw new MarshalException(sx);
1823 }
1824 } else if (isEnum(cls)) {
1825 char[] chars = object.toString().toCharArray();
1826 try {
1827 handler.characters(chars, 0, chars.length);
1828 } catch (org.xml.sax.SAXException sx) {
1829 throw new MarshalException(sx);
1830 }
1831
1832 }
1833 }
1834
1835
1836
1837
1838
1839 if (isNil || descriptor.isReference()) {
1840 descriptors = NO_FIELD_DESCRIPTORS;
1841 } else {
1842 descriptors = classDesc.getElementDescriptors();
1843 }
1844
1845 ++_depth;
1846
1847
1848 for (int i = firstNonNullIdx; i < descriptors.length; i++) {
1849
1850 XMLFieldDescriptor elemDescriptor = descriptors[i];
1851 Object obj = null;
1852 boolean nil = false;
1853
1854
1855 if ((i == firstNonNullIdx) && (firstNonNullValue != null)) {
1856 obj = firstNonNullValue;
1857 } else {
1858
1859 try {
1860 obj = elemDescriptor.getHandler().getValue(object);
1861 } catch (IllegalStateException ise) {
1862 LOG.warn("Error marshalling " + object, ise);
1863 continue;
1864 }
1865 }
1866
1867 if (obj == null
1868 || (obj instanceof Enumeration && !((Enumeration<?>) obj).hasMoreElements())) {
1869 if (elemDescriptor.isNillable() && (elemDescriptor.isRequired())) {
1870 nil = true;
1871 } else {
1872 continue;
1873 }
1874 }
1875
1876
1877
1878 String path = elemDescriptor.getLocationPath();
1879 String currentLoc = null;
1880
1881 if (wrappers != null) {
1882 try {
1883 while (!wrappers.empty()) {
1884 WrapperInfo wInfo = wrappers.peek();
1885 if (path != null) {
1886 if (wInfo._location.equals(path)) {
1887 path = null;
1888 break;
1889 } else if (path.startsWith(wInfo._location + "/")) {
1890 path = path.substring(wInfo._location.length() + 1);
1891 currentLoc = wInfo._location;
1892 break;
1893 }
1894 }
1895 handler.endElement(nsURI, wInfo._localName, wInfo._qName);
1896 wrappers.pop();
1897 }
1898 } catch (SAXException sx) {
1899 throw new MarshalException(sx);
1900 }
1901 }
1902
1903
1904 if (path != null) {
1905 _attributes.clear();
1906 if (wrappers == null) {
1907 wrappers = new SafeStack<WrapperInfo>();
1908 }
1909 try {
1910 while (path != null) {
1911
1912 String elemName = null;
1913 int idx = path.indexOf('/');
1914
1915 if (idx > 0) {
1916 elemName = path.substring(0, idx);
1917 path = path.substring(idx + 1);
1918 } else {
1919 elemName = path;
1920 path = null;
1921 }
1922
1923
1924
1925 if (currentLoc == null)
1926 currentLoc = elemName;
1927 else
1928 currentLoc = currentLoc + "/" + elemName;
1929
1930 String elemQName = elemName;
1931 if (StringUtils.isNotEmpty(nsPrefix)) {
1932 elemQName = nsPrefix + ':' + elemName;
1933 }
1934 wrappers.push(new WrapperInfo(elemName, elemQName, currentLoc));
1935
1936
1937 _attributes.clear();
1938 if (nestedAttCount > 0) {
1939 for (int na = 0; na < nestedAtts.length; na++) {
1940 if (nestedAtts[na] == null)
1941 continue;
1942 String tmpPath = nestedAtts[na].getLocationPath();
1943 if (tmpPath.equals(currentLoc)) {
1944 processAttribute(object, nestedAtts[na], _attributes);
1945 nestedAtts[na] = null;
1946 --nestedAttCount;
1947 }
1948 }
1949 }
1950 handler.startElement(nsURI, elemName, elemQName, _attributes);
1951 }
1952 } catch (SAXException sx) {
1953 throw new MarshalException(sx);
1954 }
1955 }
1956
1957 if (nil) {
1958 obj = new NilObject(classDesc, elemDescriptor);
1959 }
1960
1961 final Class<?> type = obj.getClass();
1962
1963 MarshalState myState = mstate.createMarshalState(object, name);
1964 myState._nestedAtts = nestedAtts;
1965 myState._nestedAttCount = nestedAttCount;
1966
1967
1968
1969 if (type.isArray() && (type.getComponentType() == Byte.TYPE)) {
1970 marshal(obj, elemDescriptor, handler, myState);
1971 } else if (type.isArray() && elemDescriptor.isDerivedFromXSList()) {
1972 Object buffer = processXSListType(obj, elemDescriptor);
1973 String elemName = elemDescriptor.getXMLName();
1974 String elemQName = elemName;
1975 if (StringUtils.isNotEmpty(nsPrefix)) {
1976 elemQName = nsPrefix + ':' + elemName;
1977 }
1978 char[] chars = buffer.toString().toCharArray();
1979 try {
1980 handler.startElement(nsURI, elemName, elemQName, _attributes);
1981 handler.characters(chars, 0, chars.length);
1982 handler.endElement(nsURI, elemName, elemQName);
1983 } catch (org.xml.sax.SAXException sx) {
1984 throw new MarshalException(sx);
1985 }
1986 }
1987
1988 else if (isCollection(type)) {
1989 boolean processCollection = true;
1990 if (_saveMapKeys) {
1991 MapHandler mapHandler = MapHandlers.getHandler(type);
1992 if (mapHandler != null) {
1993 processCollection = false;
1994 MapItem item = new MapItem();
1995 Enumeration<?> keys = mapHandler.keys(obj);
1996 while (keys.hasMoreElements()) {
1997 item.setKey(keys.nextElement());
1998 item.setValue(mapHandler.get(obj, item.getKey()));
1999 marshal(item, elemDescriptor, handler, myState);
2000 }
2001 }
2002
2003 }
2004 if (processCollection) {
2005 CollectionHandler<?> colHandler = getCollectionHandler(type);
2006 Enumeration<?> enumeration = colHandler.elements(obj);
2007 while (enumeration.hasMoreElements()) {
2008 Object item = enumeration.nextElement();
2009 if (item != null) {
2010 marshal(item, elemDescriptor, handler, myState);
2011 }
2012 }
2013 }
2014 }
2015
2016 else {
2017 marshal(obj, elemDescriptor, handler, myState);
2018 }
2019
2020 if (nestedAttCount > 0) {
2021 nestedAttCount = myState._nestedAttCount;
2022 }
2023
2024 }
2025
2026
2027
2028 if (wrappers != null) {
2029 try {
2030 while (!wrappers.empty()) {
2031 WrapperInfo wInfo = wrappers.peek();
2032 boolean popStack = true;
2033 if (nestedAttCount > 0) {
2034 for (int na = 0; na < nestedAtts.length; na++) {
2035
2036 if (nestedAtts[na] == null)
2037 continue;
2038 String nestedAttributePath = nestedAtts[na].getLocationPath();
2039 if (nestedAttributePath.startsWith(wInfo._location + "/")) {
2040 popStack = false;
2041 break;
2042 }
2043 }
2044 }
2045 if (popStack) {
2046 handler.endElement(nsURI, wInfo._localName, wInfo._qName);
2047 wrappers.pop();
2048 } else {
2049 break;
2050 }
2051 }
2052 } catch (SAXException sx) {
2053 throw new MarshalException(sx);
2054 }
2055 }
2056
2057
2058
2059
2060
2061 if (wrappers != null && !wrappers.isEmpty()) {
2062 dealWithNestedAttributesNested(object, handler, nsPrefix, nsURI, nestedAttCount, nestedAtts,
2063 wrappers);
2064 }
2065
2066 dealWithNestedAttributes(object, handler, nsPrefix, nsURI, nestedAttCount, nestedAtts,
2067 new SafeStack<WrapperInfo>());
2068
2069
2070 try {
2071 if (!containerField) {
2072 handler.endElement(nsURI, name, qName);
2073
2074 namespacesStack.getCurrentNamespaceScope().sendEndEvents(handler);
2075 }
2076 } catch (org.xml.sax.SAXException sx) {
2077 throw new MarshalException(sx);
2078 }
2079
2080 --_depth;
2081 _parents.pop();
2082 if (!atRoot) {
2083 namespacesStack.removeNamespaceScope();
2084 }
2085
2086
2087 if (_marshalListener != null) {
2088 try {
2089 _marshalListener.postMarshal(object);
2090 } catch (RuntimeException e) {
2091 LOG.error(
2092 "Invoking #postMarshal() on your custom MarshalListener instance caused the following problem:",
2093 e);
2094 }
2095 }
2096
2097 }
2098
2099 private void dealWithNestedAttributes(Object object, ContentHandler handler, String nsPrefix,
2100 String nsURI, int nestedAttCount, XMLFieldDescriptor[] nestedAtts,
2101 Stack<WrapperInfo> wrappers) throws MarshalException {
2102
2103
2104 if (nestedAttCount > 0) {
2105 for (int i = 0; i < nestedAtts.length; i++) {
2106 if (nestedAtts[i] == null)
2107 continue;
2108 String path = nestedAtts[i].getLocationPath();
2109 String currentLoc = null;
2110
2111
2112
2113
2114
2115
2116
2117 if (nestedAtts[i].getHandler().getValue(object) == null) {
2118 nestedAtts[i] = null;
2119 --nestedAttCount;
2120 continue;
2121 }
2122 try {
2123 while (path != null) {
2124 int idx = path.indexOf('/');
2125 String elemName = null;
2126 if (idx > 0) {
2127 elemName = path.substring(0, idx);
2128 path = path.substring(idx + 1);
2129 } else {
2130 elemName = path;
2131 path = null;
2132 }
2133 if (currentLoc == null)
2134 currentLoc = elemName;
2135 else
2136 currentLoc = currentLoc + "/" + elemName;
2137
2138 String elemQName = elemName;
2139 if (StringUtils.isNotEmpty(nsPrefix)) {
2140 elemQName = nsPrefix + ':' + elemName;
2141 }
2142 wrappers.push(new WrapperInfo(elemName, elemQName, null));
2143
2144 _attributes.clear();
2145 if (path == null) {
2146 processAttribute(object, nestedAtts[i], _attributes);
2147 nestedAtts[i] = null;
2148 --nestedAttCount;
2149 }
2150 if (nestedAttCount > 0) {
2151 for (int na = i + 1; na < nestedAtts.length; na++) {
2152 if (nestedAtts[na] == null)
2153 continue;
2154 String tmpPath = nestedAtts[na].getLocationPath();
2155 if (tmpPath.equals(currentLoc)) {
2156 processAttribute(object, nestedAtts[na], _attributes);
2157 nestedAtts[na] = null;
2158 --nestedAttCount;
2159 }
2160 }
2161 }
2162 handler.startElement(nsURI, elemName, elemQName, _attributes);
2163 }
2164
2165 while (!wrappers.empty()) {
2166 WrapperInfo wInfo = wrappers.pop();
2167 handler.endElement(nsURI, wInfo._localName, wInfo._qName);
2168 }
2169 } catch (Exception e) {
2170 throw new MarshalException(e);
2171 }
2172 }
2173 }
2174 }
2175
2176 private void dealWithNestedAttributesNested(Object object, ContentHandler handler,
2177 String nsPrefix, String nsURI, int nestedAttCount, XMLFieldDescriptor[] nestedAtts,
2178 Stack<WrapperInfo> wrappers) throws MarshalException {
2179
2180
2181
2182 WrapperInfo wrapperInfo = wrappers.peek();
2183 String currentLocation = wrapperInfo._location;
2184
2185 if (nestedAttCount > 0) {
2186 for (int i = 0; i < nestedAtts.length; i++) {
2187 if (nestedAtts[i] == null)
2188 continue;
2189 String nestedAttributePath = nestedAtts[i].getLocationPath();
2190
2191 if (!nestedAttributePath.startsWith(currentLocation + "/")) {
2192 continue;
2193 }
2194
2195 nestedAttributePath = nestedAttributePath.substring(wrapperInfo._location.length() + 1);
2196 String currentLoc = currentLocation;
2197
2198
2199
2200
2201
2202
2203
2204 if (nestedAtts[i].getHandler().getValue(object) == null) {
2205 nestedAtts[i] = null;
2206 --nestedAttCount;
2207 continue;
2208 }
2209 try {
2210 while (nestedAttributePath != null) {
2211 int idx = nestedAttributePath.indexOf('/');
2212 String elemName = null;
2213 if (idx > 0) {
2214 elemName = nestedAttributePath.substring(0, idx);
2215 nestedAttributePath = nestedAttributePath.substring(idx + 1);
2216 } else {
2217 elemName = nestedAttributePath;
2218 nestedAttributePath = null;
2219 }
2220 if (currentLoc == null)
2221 currentLoc = elemName;
2222 else
2223 currentLoc = currentLoc + "/" + elemName;
2224
2225 String elemQName = elemName;
2226 if (StringUtils.isNotEmpty(nsPrefix)) {
2227 elemQName = nsPrefix + ':' + elemName;
2228 }
2229 wrappers.push(new WrapperInfo(elemName, elemQName, null));
2230
2231 _attributes.clear();
2232 if (nestedAttributePath == null) {
2233 processAttribute(object, nestedAtts[i], _attributes);
2234 nestedAtts[i] = null;
2235 --nestedAttCount;
2236 }
2237 if (nestedAttCount > 0) {
2238 for (int na = i + 1; na < nestedAtts.length; na++) {
2239 if (nestedAtts[na] == null)
2240 continue;
2241 String tmpPath = nestedAtts[na].getLocationPath();
2242 if (tmpPath.equals(currentLoc)) {
2243 processAttribute(object, nestedAtts[na], _attributes);
2244 nestedAtts[na] = null;
2245 --nestedAttCount;
2246 }
2247 }
2248 }
2249 handler.startElement(nsURI, elemName, elemQName, _attributes);
2250 }
2251
2252 while (!wrappers.empty()) {
2253 WrapperInfo wInfo = wrappers.pop();
2254 handler.endElement(nsURI, wInfo._localName, wInfo._qName);
2255 }
2256 } catch (Exception e) {
2257 throw new MarshalException(e);
2258 }
2259 }
2260 }
2261 }
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273 private String convertBigDecimalToString(Object object) throws MarshalException {
2274 String stringValue;
2275 float javaVersion = Float.parseFloat(System.getProperty("java.specification.version"));
2276 if (javaVersion >= 1.5) {
2277
2278
2279 Method method;
2280 try {
2281 method = java.math.BigDecimal.class.getMethod("toPlainString", (Class[]) null);
2282 stringValue = (String) method.invoke(object, (Object[]) null);
2283 } catch (Exception e) {
2284 LOG.error("Problem accessing java.math.BigDecimal.toPlainString().", e);
2285 throw new MarshalException("Problem accessing java.math.BigDecimal.toPlainString().", e);
2286 }
2287 } else {
2288
2289 stringValue = object.toString();
2290 }
2291 return stringValue;
2292 }
2293
2294
2295
2296
2297
2298
2299
2300 private Object getObjectID(Object object) throws MarshalException {
2301 if (object == null)
2302 return null;
2303
2304 Object id = null;
2305 XMLClassDescriptor cd = getClassDescriptor(object.getClass());
2306 String err = null;
2307 if (cd != null) {
2308 XMLFieldDescriptor fieldDesc = (XMLFieldDescriptor) cd.getIdentity();
2309 if (fieldDesc != null) {
2310 FieldHandler<?> fieldHandler = fieldDesc.getHandler();
2311 if (fieldHandler != null) {
2312 try {
2313 id = fieldHandler.getValue(object);
2314 } catch (IllegalStateException ise) {
2315 err = ise.toString();
2316 }
2317 }
2318 else {
2319 err = "FieldHandler for Identity descriptor is null.";
2320 }
2321 }
2322 else
2323 err = "No identity descriptor available";
2324 }
2325 else {
2326 err = "Unable to resolve ClassDescriptor.";
2327 }
2328 if (err != null) {
2329 String errMsg = "Unable to resolve ID for instance of class '";
2330 errMsg += object.getClass().getName();
2331 errMsg += "' due to the following error: ";
2332 throw new MarshalException(errMsg + err);
2333 }
2334 return id;
2335 }
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345 private boolean declareNamespace(String nsPrefix, String nsURI) {
2346 boolean declared = false;
2347
2348
2349 if ((nsURI != null) && (nsURI.length() != 0)) {
2350
2351 String tmpURI = namespacesStack.getNamespaceURI(nsPrefix);
2352 if ((tmpURI != null) && (tmpURI.equals(nsURI))) {
2353 return declared;
2354 }
2355 String tmpPrefix = namespacesStack.getNamespacePrefix(nsURI);
2356 if ((tmpPrefix == null) || (!tmpPrefix.equals(nsPrefix))) {
2357 namespacesStack.addNamespace(nsPrefix, nsURI);
2358 declared = true;
2359 }
2360 }
2361 return declared;
2362 }
2363
2364
2365
2366
2367
2368
2369 public void setLogWriter(final PrintWriter printWriter) {}
2370
2371
2372
2373
2374
2375
2376
2377 public void setEncoding(String encoding) {
2378
2379 if (_serializer != null) {
2380 if (_format == null) {
2381 _format = getInternalContext().getOutputFormat();
2382 }
2383 _format.setEncoding(encoding);
2384
2385
2386 _serializer.setOutputFormat(_format);
2387 try {
2388
2389
2390
2391 _handler = new DocumentHandlerAdapter(_serializer.asDocumentHandler());
2392 } catch (java.io.IOException iox) {
2393
2394
2395
2396
2397 if (LOG.isDebugEnabled()) {
2398 LOG.debug("Error setting encoding to " + encoding, iox);
2399 }
2400 }
2401 } else {
2402 String error = "encoding cannot be set if you've passed in " + "your own DocumentHandler";
2403 throw new IllegalStateException(error);
2404 }
2405 }
2406
2407
2408
2409
2410
2411
2412
2413
2414 public void setNoNamespaceSchemaLocation(String schemaLocation) {
2415 if (schemaLocation == null) {
2416
2417
2418 } else {
2419 _topLevelAtts.setAttribute(XSI_NO_NAMESPACE_SCHEMA_LOCATION, schemaLocation, XSI_NAMESPACE);
2420 }
2421 }
2422
2423
2424
2425
2426
2427
2428
2429
2430 public void setSchemaLocation(String schemaLocation) {
2431 if (schemaLocation == null) {
2432
2433
2434 } else {
2435 _topLevelAtts.setAttribute(XSI_SCHEMA_LOCATION, schemaLocation, XSI_NAMESPACE);
2436 }
2437 }
2438
2439
2440
2441
2442
2443
2444
2445
2446 public void setSuppressNamespaces(boolean suppressNamespaces) {
2447 _suppressNamespaces = suppressNamespaces;
2448 }
2449
2450
2451
2452
2453
2454
2455
2456 public void setSuppressXSIType(boolean suppressXSIType) {
2457 _suppressXSIType = suppressXSIType;
2458 }
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468 public void setUseXSITypeAtRoot(boolean useXSITypeAtRoot) {
2469 _useXSITypeAtRoot = useXSITypeAtRoot;
2470 }
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480 private XMLClassDescriptor getClassDescriptor(final Class<?> cls) throws MarshalException {
2481 XMLClassDescriptor classDesc = null;
2482
2483 try {
2484 if (!isPrimitive(cls))
2485 classDesc = (XMLClassDescriptor) getResolver().resolve(cls);
2486 } catch (ResolverException rx) {
2487 Throwable actual = rx.getCause();
2488 if (actual instanceof MarshalException) {
2489 throw (MarshalException) actual;
2490 }
2491 if (actual != null) {
2492 throw new MarshalException(actual);
2493 }
2494 throw new MarshalException(rx);
2495 }
2496
2497 if (classDesc != null)
2498 classDesc = new InternalXMLClassDescriptor(classDesc);
2499
2500 return classDesc;
2501 }
2502
2503
2504
2505
2506
2507
2508 private void processAttribute(Object object, XMLFieldDescriptor attDescriptor,
2509 AttributesImpl atts) throws MarshalException {
2510 if (attDescriptor == null)
2511 return;
2512
2513
2514
2515 if (attDescriptor.getNodeType() == NodeType.Namespace) {
2516 if (!_suppressNamespaces) {
2517 Object map = attDescriptor.getHandler().getValue(object);
2518 MapHandler mapHandler = MapHandlers.getHandler(map);
2519 if (mapHandler != null) {
2520 Enumeration<?> keys = mapHandler.keys(map);
2521 while (keys.hasMoreElements()) {
2522 Object key = keys.nextElement();
2523 Object val = mapHandler.get(map, key);
2524 declareNamespace(key.toString(), val.toString());
2525 }
2526 }
2527 }
2528 return;
2529 }
2530
2531 String localName = attDescriptor.getXMLName();
2532 String qName = localName;
2533
2534
2535 String namespace = "";
2536 if (!_suppressNamespaces) {
2537 namespace = attDescriptor.getNameSpaceURI();
2538 if (StringUtils.isNotEmpty(namespace)) {
2539 String prefix = attDescriptor.getNameSpacePrefix();
2540 if ((prefix == null) || (prefix.length() == 0))
2541 prefix = namespacesStack.getNonDefaultNamespacePrefix(namespace);
2542
2543 if ((prefix == null) || (prefix.length() == 0)) {
2544
2545 prefix = DEFAULT_PREFIX + (++_namespaceCounter);
2546 }
2547 declareNamespace(prefix, namespace);
2548 qName = prefix + ':' + qName;
2549 } else
2550 namespace = "";
2551 }
2552
2553 Object value = null;
2554
2555 try {
2556 value = attDescriptor.getHandler().getValue(object);
2557 } catch (IllegalStateException ise) {
2558 LOG.warn("Error getting value from " + object, ise);
2559 return;
2560 }
2561
2562
2563 if (attDescriptor.isReference() && (value != null)) {
2564
2565 if (attDescriptor.isMultivalued()) {
2566 Enumeration<?> enumeration = null;
2567 if (value instanceof Enumeration) {
2568 enumeration = (Enumeration<?>) value;
2569 } else {
2570 CollectionHandler<?> colHandler = null;
2571 try {
2572 colHandler = CollectionHandlers.getHandler(value.getClass());
2573 } catch (MappingException mx) {
2574 throw new MarshalException(mx);
2575 }
2576 enumeration = colHandler.elements(value);
2577 }
2578 if (enumeration.hasMoreElements()) {
2579 StringBuilder sb = new StringBuilder();
2580 for (int v = 0; enumeration.hasMoreElements(); v++) {
2581 if (v > 0)
2582 sb.append(' ');
2583 sb.append(getObjectID(enumeration.nextElement()));
2584 }
2585 value = sb;
2586 } else
2587 value = null;
2588 } else {
2589 value = getObjectID(value);
2590 }
2591 }
2592
2593 else if (attDescriptor.isMultivalued() && (value != null)) {
2594 value = processXSListType(value, attDescriptor);
2595 } else if (value != null) {
2596
2597 Class<?> objType = value.getClass();
2598 if (objType.isArray() && (objType.getComponentType() == Byte.TYPE)) {
2599 value = encodeBinaryData(value, attDescriptor.getSchemaType());
2600 }
2601 }
2602
2603 if (value != null) {
2604
2605
2606 String valueType = attDescriptor.getSchemaType();
2607 if ((valueType != null) && (valueType.equals(QNAME_NAME)))
2608 value = resolveQName(value, attDescriptor);
2609
2610 atts.addAttribute(namespace, localName, qName, CDATA, value.toString());
2611 }
2612 }
2613
2614 private Object processXSListType(final Object value, XMLFieldDescriptor descriptor)
2615 throws MarshalException {
2616 Object returnValue = null;
2617 Enumeration<?> enumeration = null;
2618 if (value instanceof Enumeration) {
2619 enumeration = (Enumeration<?>) value;
2620 } else {
2621 CollectionHandler<?> colHandler = null;
2622 try {
2623 colHandler = CollectionHandlers.getHandler(value.getClass());
2624 } catch (MappingException mx) {
2625 throw new MarshalException(mx);
2626 }
2627 enumeration = colHandler.elements(value);
2628 }
2629 if (enumeration.hasMoreElements()) {
2630 StringBuilder sb = new StringBuilder();
2631 for (int v = 0; enumeration.hasMoreElements(); v++) {
2632 if (v > 0) {
2633 sb.append(' ');
2634 }
2635 Object collectionValue = enumeration.nextElement();
2636
2637 Class<?> objType = collectionValue.getClass();
2638 if (objType.isArray() && (objType.getComponentType() == Byte.TYPE)) {
2639 collectionValue = encodeBinaryData(collectionValue, descriptor.getComponentType());
2640 }
2641
2642 sb.append(collectionValue);
2643 }
2644 returnValue = sb;
2645 }
2646
2647 return returnValue;
2648 }
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658 private Object encodeBinaryData(final Object valueToEncode, final String componentType) {
2659 String encodedValue;
2660 if (HexDecoder.DATA_TYPE.equals(componentType)) {
2661 encodedValue = HexDecoder.encode((byte[]) valueToEncode);
2662 } else {
2663 encodedValue = new String(Base64Encoder.encode((byte[]) valueToEncode));
2664 }
2665 return encodedValue;
2666 }
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676 private void processContainerAttributes(Object target, XMLClassDescriptor classDesc,
2677 AttributesImpl atts) throws MarshalException {
2678 if (classDesc instanceof XMLClassDescriptorImpl) {
2679 if (!((XMLClassDescriptorImpl) classDesc).hasContainerFields())
2680 return;
2681 }
2682
2683 XMLFieldDescriptor[] elemDescriptors = classDesc.getElementDescriptors();
2684 for (int i = 0; i < elemDescriptors.length; i++) {
2685 if (elemDescriptors[i] == null)
2686 continue;
2687 if (!elemDescriptors[i].isContainer())
2688 continue;
2689 processContainerAttributes(target, elemDescriptors[i], atts);
2690 }
2691 }
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701 private void processContainerAttributes(final Object target,
2702 final XMLFieldDescriptor containerFieldDesc, final AttributesImpl atts)
2703 throws MarshalException {
2704 if (target.getClass().isArray()) {
2705 int length = Array.getLength(target);
2706 for (int j = 0; j < length; j++) {
2707 Object item = Array.get(target, j);
2708 if (item != null) {
2709 processContainerAttributes(item, containerFieldDesc, atts);
2710 }
2711 }
2712 return;
2713 } else if (target instanceof Enumeration) {
2714 Enumeration<?> enumeration = (Enumeration<?>) target;
2715 while (enumeration.hasMoreElements()) {
2716 Object item = enumeration.nextElement();
2717 if (item != null) {
2718 processContainerAttributes(item, containerFieldDesc, atts);
2719 }
2720 }
2721 return;
2722 }
2723
2724 Object containerObject = containerFieldDesc.getHandler().getValue(target);
2725
2726 if (containerObject == null) {
2727 return;
2728 }
2729
2730 XMLClassDescriptor containerClassDesc =
2731 (XMLClassDescriptor) containerFieldDesc.getClassDescriptor();
2732
2733 if (containerClassDesc == null) {
2734 containerClassDesc = getClassDescriptor(containerFieldDesc.getFieldType());
2735 if (containerClassDesc == null) {
2736 return;
2737 }
2738 }
2739
2740
2741 XMLFieldDescriptor[] attrDescriptors = containerClassDesc.getAttributeDescriptors();
2742 for (int idx = 0; idx < attrDescriptors.length; idx++) {
2743 if (attrDescriptors[idx] == null) {
2744 continue;
2745 }
2746 if (attrDescriptors[idx].getLocationPath() == null
2747 || attrDescriptors[idx].getLocationPath().length() == 0) {
2748 processAttribute(containerObject, attrDescriptors[idx], atts);
2749 }
2750 }
2751
2752
2753 processContainerAttributes(containerObject, containerClassDesc, atts);
2754 }
2755
2756
2757
2758
2759 private Object resolveQName(Object value, XMLFieldDescriptor fieldDesc) {
2760 if ((value == null) || !(value instanceof String))
2761 return value;
2762 if (!(fieldDesc instanceof XMLFieldDescriptorImpl))
2763 return value;
2764
2765 String result = (String) value;
2766
2767 String nsURI = null;
2768 int idx = -1;
2769 if ((result.length() > 0) && (result.charAt(0) == '{')) {
2770 idx = result.indexOf('}');
2771 if (idx <= 0) {
2772 String err = "Bad QName value :'" + result + "', it should follow the pattern '{URI}value'";
2773 throw new IllegalArgumentException(err);
2774 }
2775 nsURI = result.substring(1, idx);
2776 } else
2777 return value;
2778
2779 String prefix = ((XMLFieldDescriptorImpl) fieldDesc).getQNamePrefix();
2780
2781 if (prefix == null)
2782 prefix = namespacesStack.getNamespacePrefix(nsURI);
2783
2784 if (prefix == null)
2785 prefix = DEFAULT_PREFIX + (++_namespaceCounter);
2786 result = (prefix.length() != 0) ? prefix + ":" + result.substring(idx + 1)
2787 : result.substring(idx + 1);
2788 declareNamespace(prefix, nsURI);
2789 return result;
2790 }
2791
2792 private void validate(final Object object) throws ValidationException {
2793 if (_validate) {
2794
2795 Validator validator = new Validator();
2796 ValidationContext context = new ValidationContext();
2797 context.setInternalContext(getInternalContext());
2798
2799
2800 validator.validate(object, context);
2801 }
2802 }
2803
2804
2805
2806
2807
2808
2809
2810
2811 public String getProperty(final String name) {
2812 return getInternalContext().getStringProperty(name);
2813 }
2814
2815
2816
2817
2818
2819
2820
2821
2822 public void setProperty(final String name, final String value) {
2823 getInternalContext().setProperty(name, value);
2824 deriveProperties();
2825 }
2826
2827
2828
2829
2830 static class WrapperInfo {
2831 private String _localName = null;
2832 private String _qName = null;
2833 private String _location = null;
2834
2835 WrapperInfo(final String localName, final String qName, final String location) {
2836 _localName = localName;
2837 _qName = qName;
2838 _location = location;
2839 }
2840 }
2841
2842
2843 static class MarshalState {
2844 private String _xpath = null;
2845 private XMLFieldDescriptor[] _nestedAtts = null;
2846 private int _nestedAttCount = 0;
2847 private MarshalState _parent = null;
2848 private Object _owner = null;
2849 private String _xmlName = null;
2850
2851 MarshalState(Object owner, String xmlName) {
2852 checkNotNull(owner, "The argument 'owner' must not be null.");
2853 checkNotNull(xmlName, "The argument 'xmlName' must not be null.");
2854
2855 _owner = owner;
2856 _xmlName = xmlName;
2857 }
2858
2859
2860 MarshalState createMarshalState(Object owner, String xmlName) {
2861 MarshalState ms = new MarshalState(owner, xmlName);
2862 ms._parent = this;
2863 return ms;
2864 }
2865
2866 String getXPath() {
2867 if (_xpath == null) {
2868 if (_parent != null) {
2869 _xpath = _parent.getXPath() + "/" + _xmlName;
2870 } else {
2871 _xpath = _xmlName;
2872 }
2873 }
2874 return _xpath;
2875 }
2876
2877 Object getOwner() {
2878 return _owner;
2879 }
2880
2881 MarshalState getParent() {
2882 return _parent;
2883 }
2884 }
2885
2886
2887
2888
2889
2890 public static class NilObject {
2891
2892 private XMLClassDescriptor _classDesc = null;
2893 private XMLFieldDescriptor _fieldDesc = null;
2894
2895 NilObject(XMLClassDescriptor classDesc, XMLFieldDescriptor fieldDesc) {
2896 _classDesc = classDesc;
2897 _fieldDesc = fieldDesc;
2898 }
2899
2900
2901
2902
2903
2904
2905 public XMLClassDescriptor getClassDescriptor() {
2906 return _classDesc;
2907 }
2908
2909
2910
2911
2912
2913
2914 public XMLFieldDescriptor getFieldDescriptor() {
2915 return _fieldDesc;
2916 }
2917 }
2918
2919
2920
2921
2922
2923
2924 public void setContentHandler(final ContentHandler contentHandler) {
2925 _handler = contentHandler;
2926 }
2927
2928
2929
2930
2931 private void setDocumentHandler() {
2932 try {
2933
2934
2935
2936 _handler = new DocumentHandlerAdapter(_serializer.asDocumentHandler());
2937 } catch (IOException iox) {
2938
2939
2940
2941
2942 if (LOG.isDebugEnabled()) {
2943 LOG.debug("Error setting up document handler", iox);
2944 }
2945 }
2946 }
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957 private static void checkNotEmpty(String param, String msg) {
2958 checkNotNull(param, msg);
2959
2960 if (param.length() == 0) {
2961 throw new IllegalArgumentException(msg);
2962 }
2963 }
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974 private static void checkNotNull(Object param, String msg) {
2975
2976 if (param == null) {
2977 throw new IllegalArgumentException(msg);
2978 }
2979 }
2980 }
2981
2982