1 /*
2 * Copyright 2010 Werner Guttmann
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.exolab.castor.xml;
17
18 import java.text.MessageFormat;
19 import java.util.Locale;
20 import java.util.ResourceBundle;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.castor.xml.XMLProperties;
26 import org.exolab.castor.mapping.ExtendedFieldHandler;
27 import org.exolab.castor.mapping.FieldHandler;
28 import org.exolab.castor.mapping.loader.FieldHandlerImpl;
29 import org.exolab.castor.xml.MarshalFramework.InheritanceMatch;
30 import org.exolab.castor.xml.MarshalFramework.InternalXMLClassDescriptor;
31 import org.exolab.castor.xml.UnmarshalHandler.Arguments;
32 import org.exolab.castor.xml.UnmarshalHandler.ArrayHandler;
33 import org.exolab.castor.xml.util.ContainerElement;
34 import org.exolab.castor.xml.util.XMLClassDescriptorImpl;
35 import org.xml.sax.ContentHandler;
36 import org.xml.sax.SAXException;
37
38 /**
39 * A processor that assists {@link UnmarshalHandler} in dealing with the SAX 2
40 * {@link ContentHandler#startElement(String, String, String, org.xml.sax.Attributes)}
41 * callback method.
42 *
43 * @author <a href=" mailto:wguttmn AT codehaus DOT org">Werner Guttmann</a>
44 * @since 1.3.2
45 */
46 public class StartElementProcessor {
47
48 /**
49 * Standard logger to use.
50 */
51 private static final Log LOG = LogFactory
52 .getLog(StartElementProcessor.class);
53
54 /**
55 * resource bundle
56 */
57 protected static ResourceBundle resourceBundle;
58
59 /**
60 * Callback {@link UnmarshalHandler} reference to set the actual state on
61 * this instance.
62 */
63 private final UnmarshalHandler _unmarshalHandler;
64
65 static {
66 resourceBundle = ResourceBundle.getBundle("UnmarshalHandlerMessages",
67 Locale.getDefault());
68 }
69
70 /**
71 * Creates an instance of this class, with a reference to the actual
72 * {@link UnmarshalHandler} for which this processor deals with the SAX 2
73 * startElement() callback method.
74 *
75 * @param unmarshalHandler
76 * The {@link UnmarshalHandler} instance on which the results of
77 * processing the startElement method will be 'persisted'/set.
78 */
79 public StartElementProcessor(final UnmarshalHandler unmarshalHandler) {
80 super();
81 _unmarshalHandler = unmarshalHandler;
82 }
83
84 public void compute(String name, String namespace, AttributeSet atts)
85 throws SAXException {
86
87 UnmarshalState state = null;
88 String xmlSpace = null;
89
90 // -- handle special atts
91 if (atts != null) {
92 // -- xml:space
93 xmlSpace = atts.getValue(UnmarshalHandler.XML_SPACE,
94 Namespaces.XML_NAMESPACE);
95 if (xmlSpace == null) {
96 xmlSpace = atts.getValue(
97 UnmarshalHandler.XML_SPACE_WITH_PREFIX, "");
98 }
99 }
100
101 if (_unmarshalHandler.getStateStack().isEmpty()) {
102 // -- Initialize since this is the first element
103 _unmarshalHandler.processFirstElement(name, namespace, atts,
104 xmlSpace);
105 return;
106 } // --rootElement
107
108 // -- get MarshalDescriptor for the given element
109 UnmarshalState parentState = _unmarshalHandler.getStateStack()
110 .getLastState();
111
112 // Test if we can accept the field in the parentState
113 // in case the parentState fieldDesc is a container
114 // -- This following logic tests to see if we are in a
115 // -- container and we need to close out the container
116 // -- before proceeding:
117 boolean canAccept = false;
118 while ((parentState.getFieldDescriptor() != null)
119 && (parentState.getFieldDescriptor().isContainer() && !canAccept)) {
120 XMLClassDescriptor tempClassDesc = parentState.getClassDescriptor();
121
122 // -- Find ClassDescriptor for Parent
123 if (tempClassDesc == null) {
124 tempClassDesc = (XMLClassDescriptor) parentState.getFieldDescriptor()
125 .getClassDescriptor();
126 if (tempClassDesc == null)
127 tempClassDesc = _unmarshalHandler
128 .getClassDescriptor(parentState.getObject().getClass());
129 }
130
131 canAccept = tempClassDesc.canAccept(name, namespace,
132 parentState.getObject());
133
134 if (!canAccept) {
135 // -- Does container class even handle this field?
136 if (tempClassDesc.getFieldDescriptor(name, namespace,
137 NodeType.Element) != null) {
138 if (!parentState.getFieldDescriptor().isMultivalued()) {
139 String error = MessageFormat
140 .format(resourceBundle
141 .getString("unmarshalHandler.error.container.full"),
142 new Object[] {
143 tempClassDesc.getJavaClass()
144 .getName(), name });
145 ValidationException vx = new ValidationException(error);
146 throw new SAXException(vx);
147 }
148 }
149 _unmarshalHandler.endElement(parentState.getElementName());
150 parentState = _unmarshalHandler.getStateStack().getLastState();
151 }
152 tempClassDesc = null;
153 }
154
155 // -- create new state object
156 state = new UnmarshalState();
157 state.setElementName(name);
158 state.setParent(parentState);
159
160 if (xmlSpace != null) {
161 state.setWhitespacePreserving(UnmarshalHandler.PRESERVE.equals(xmlSpace));
162 } else {
163 state.setWhitespacePreserving(parentState.isWhitespacePreserving());
164 }
165
166 _unmarshalHandler.getStateStack().pushState(state);
167
168 // -- make sure we should proceed
169 if (parentState.getObject() == null) {
170 if (!parentState.isWrapper()) {
171 return;
172 }
173 }
174
175 Class cls = null;
176
177 // -- Find ClassDescriptor for Parent
178 XMLClassDescriptor classDesc = parentState.getClassDescriptor();
179 if (classDesc == null) {
180 classDesc = (XMLClassDescriptor) parentState.getFieldDescriptor().getClassDescriptor();
181 if (classDesc == null)
182 classDesc = _unmarshalHandler.getClassDescriptor(parentState.getObject().getClass());
183 } else {
184 // classDesc.resetElementCount();
185 }
186
187 // ----------------------------------------------------/
188 // - Find FieldDescriptor associated with the element -/
189 // ----------------------------------------------------/
190
191 // -- A reference to the FieldDescriptor associated
192 // -- the the "current" element
193 XMLFieldDescriptor descriptor = null;
194
195 // -- inherited class descriptor
196 // -- (only needed if descriptor cannot be found directly)
197 XMLClassDescriptor cdInherited = null;
198
199 // -- loop through stack and find correct descriptor
200 // int pIdx = _stateInfo.size() - 2; //-- index of parentState
201 UnmarshalState targetState = parentState;
202 String path = "";
203 StringBuffer pathBuf = null;
204 int count = 0;
205 boolean isWrapper = false;
206 XMLClassDescriptor oldClassDesc = classDesc;
207 while (descriptor == null) {
208
209 // -- NOTE (kv 20050228):
210 // -- we need to clean this code up, I made this
211 // -- fix to make sure the correct descriptor which
212 // -- matches the location path is used
213 if (path.length() > 0) {
214 String tmpName = path + "/" + name;
215 descriptor = classDesc.getFieldDescriptor(tmpName, namespace,
216 NodeType.Element);
217 }
218 // -- End Patch
219
220 if (descriptor == null) {
221 descriptor = classDesc.getFieldDescriptor(name, namespace,
222 NodeType.Element);
223 }
224
225 // -- Namespace patch, should be moved to XMLClassDescriptor, but
226 // -- this is the least intrusive patch at the moment. kv - 20030423
227 if ((descriptor != null) && (!descriptor.isContainer())) {
228 if (StringUtils.isNotEmpty(namespace)) {
229 if (!MarshalFramework.namespaceEquals(namespace,
230 descriptor.getNameSpaceURI())) {
231 // -- if descriptor namespace is not null, then we must
232 // -- have a namespace match, so set descriptor to null,
233 // -- or if descriptor is not a wildcard we can also
234 // -- set to null.
235 if ((descriptor.getNameSpaceURI() != null)
236 || (!descriptor.matches("*"))) {
237 descriptor = null;
238 }
239
240 }
241 }
242 }
243 // -- end namespace patch
244
245 /*
246 * If descriptor is null, we need to handle possible inheritence,
247 * which might not be described in the current ClassDescriptor. This
248 * can be a slow process...for speed use the match attribute of the
249 * xml element in the mapping file. This logic might not be
250 * completely necessary, and perhaps we should remove it.
251 */
252 // handle multiple level locations (where count > 0) (CASTOR-1039)
253 // if ((descriptor == null) && (count == 0) &&
254 // (!targetState.wrapper)) {
255 if ((descriptor == null) && (!targetState.isWrapper())) {
256 MarshalFramework.InheritanceMatch[] matches = null;
257 try {
258 matches = _unmarshalHandler.searchInheritance(name,
259 namespace, classDesc); // TODO: Joachim,
260 // _cdResolver);
261 } catch (MarshalException rx) {
262 // -- TODO:
263 }
264 if (matches.length != 0) {
265 InheritanceMatch match = null;
266 // It may be the case that this class descriptor can
267 // appear under multiple parent field descriptors. Look
268 // for the first match whose parent file descriptor XML
269 // name matches the name of the element we are under
270 for (int i = 0; i < matches.length; i++) {
271 if (parentState.getElementName()
272 .equals(matches[i].parentFieldDesc
273 .getLocationPath())) {
274 match = matches[i];
275 break;
276 }
277 }
278 if (match == null)
279 match = matches[0];
280 descriptor = match.parentFieldDesc;
281 cdInherited = match.inheritedClassDesc;
282 break; // -- found
283 }
284 /* */
285
286 // handle multiple level locations (where count > 0)
287 // (CASTOR-1039)
288 // isWrapper = (isWrapper || hasFieldsAtLocation(name,
289 // classDesc));
290 StringBuffer tmpLocation = new StringBuffer();
291 if (count > 0) {
292 tmpLocation.append(path + "/" + name);
293 } else {
294 tmpLocation.append(name);
295 }
296 isWrapper = (isWrapper || MarshalFramework.hasFieldsAtLocation(
297 tmpLocation.toString(), classDesc));
298 } else if (descriptor != null) {
299 String tmpPath = descriptor.getLocationPath();
300 if (path.equals(StringUtils.defaultString(tmpPath)))
301 break; // -- found
302 descriptor = null; // -- not found, try again
303 } else {
304 if (pathBuf == null)
305 pathBuf = new StringBuffer();
306 else
307 pathBuf.setLength(0);
308 pathBuf.append(path);
309 pathBuf.append('/');
310 pathBuf.append(name);
311 isWrapper = (isWrapper || MarshalFramework.hasFieldsAtLocation(
312 pathBuf.toString(), classDesc));
313 }
314
315 // -- Make sure there are more parent classes on stack
316 // -- otherwise break, since there is nothing to do
317 // if (pIdx == 0) break;
318 if (targetState == _unmarshalHandler.getTopState())
319 break;
320
321 // -- adjust name and try parent
322 if (count == 0)
323 path = targetState.getElementName();
324 else {
325 if (pathBuf == null)
326 pathBuf = new StringBuffer();
327 else
328 pathBuf.setLength(0);
329 pathBuf.append(targetState.getElementName());
330 pathBuf.append('/');
331 pathBuf.append(path);
332 path = pathBuf.toString();
333 }
334
335 // -- get
336 // --pIdx;
337 // targetState = (UnmarshalState)_stateInfo.elementAt(pIdx);
338 targetState = targetState.getParent();
339 classDesc = targetState.getClassDescriptor();
340 count++;
341 }
342
343 if (descriptor != null
344 && _unmarshalHandler.isValidating()
345 && !_unmarshalHandler.getInternalContext()
346 .getLenientSequenceOrder()) {
347 try {
348 classDesc.checkDescriptorForCorrectOrderWithinSequence(
349 descriptor, parentState, name);
350 } catch (ValidationException e) {
351 throw new SAXException(e);
352 }
353 }
354
355 // -- The field descriptor is still null, we face a problem
356 if (descriptor == null) {
357
358 // -- reset classDesc
359 classDesc = oldClassDesc;
360
361 // -- isWrapper?
362 if (isWrapper) {
363 state.setClassDescriptor(new XMLClassDescriptorImpl(
364 ContainerElement.class, name));
365 state.setWrapper(true);
366 if (LOG.isDebugEnabled()) {
367 LOG.debug("wrapper-element: " + name);
368 }
369 // -- process attributes
370 _unmarshalHandler.processWrapperAttributes(atts);
371 return;
372 }
373
374 String error = MessageFormat.format(resourceBundle
375 .getString("unmarshalHandler.error.find.field.descriptor"),
376 new Object[] { name, classDesc.getXMLName() });
377
378 // -- unwrap classDesc, if necessary, for the check
379 // -- Introspector.introspected done below
380 if (classDesc instanceof InternalXMLClassDescriptor) {
381 classDesc = ((InternalXMLClassDescriptor) classDesc)
382 .getClassDescriptor();
383 }
384
385 // -- If we are skipping elements that have appeared in the XML but
386 // for
387 // -- which we have no mapping, increase the ignore depth counter
388 // and return
389 boolean lenientElementStrictnessForIntrospection = _unmarshalHandler
390 .getInternalContext()
391 .getBooleanProperty(
392 XMLProperties.LENIENT_INTROSPECTED_ELEMENT_STRICTNESS)
393 .booleanValue();
394 // checks if the element could be skipped
395 if (_unmarshalHandler.getStrictElementHandler().skipStartElementIgnoringDepth()) {
396 // -- remove the StateInfo we just added
397 _unmarshalHandler.getStateStack().removeLastState();
398 // drop Namespace instance as well
399 _unmarshalHandler.getNamespaceHandling()
400 .removeCurrentNamespaceInstance();
401 if (LOG.isDebugEnabled()) {
402 String debug = MessageFormat.format(resourceBundle
403 .getString("unmarshalHandler.log.debug.ignore.extra.element"),
404 new Object[] { error });
405 LOG.debug(debug);
406 }
407 return;
408 }
409 // if we have no field descriptor and
410 // the class descriptor was introspected
411 // just log it
412 else if (lenientElementStrictnessForIntrospection
413 && Introspector.introspected(classDesc)) {
414 LOG.warn(error);
415 return;
416 }
417 // -- otherwise report error since we cannot find a suitable
418 // -- descriptor
419 else {
420 throw new SAXException(error);
421 }
422 } // -- end null descriptor
423
424 // / DEBUG: System.out.println("path: " + path);
425
426 // -- Save targetState (used in endElement)
427 if (targetState != parentState) {
428 state.setTargetState(targetState);
429 parentState = targetState; // -- reassign
430 }
431
432 Object object = parentState.getObject();
433 // --container support
434 if (descriptor.isContainer()) {
435 // create a new state to set the container as the object
436 // don't save the current state, it will be recreated later
437
438 if (LOG.isDebugEnabled()) {
439 LOG.debug("#container: " + descriptor.getFieldName());
440 }
441
442 // -- clear current state and re-use for the container
443 state.clear();
444 // -- inherit whitespace preserving from the parentState
445 state.setWhitespacePreserving(parentState.isWhitespacePreserving());
446 state.setParent(parentState);
447
448 // here we can hard-code a name or take the field name
449 state.setElementName(descriptor.getFieldName());
450 state.setFieldDescriptor(descriptor);
451 state.setClassDescriptor((XMLClassDescriptor) descriptor
452 .getClassDescriptor());
453 Object containerObject = null;
454
455 // 1-- the container is not multivalued (not a collection)
456 if (!descriptor.isMultivalued()) {
457 // Check if the container object has already been instantiated
458 FieldHandler handler = descriptor.getHandler();
459 containerObject = handler.getValue(object);
460 if (containerObject != null) {
461 if (state.getClassDescriptor() != null) {
462 if (state.getClassDescriptor().canAccept(name, namespace,
463 containerObject)) {
464 // remove the descriptor from the used list
465 parentState.markAsNotUsed(descriptor);
466 }
467 } else {
468 // remove the descriptor from the used list
469 parentState.markAsNotUsed(descriptor);
470 }
471 } else {
472 containerObject = handler.newInstance(object);
473 }
474
475 }
476 // 2-- the container is multivalued
477 else {
478 Class containerClass = descriptor.getFieldType();
479 try {
480 containerObject = containerClass.newInstance();
481 } catch (Exception ex) {
482 throw new SAXException(ex);
483 }
484 }
485 state.setObject(containerObject);
486 state.setType(containerObject.getClass());
487
488 // we need to recall startElement()
489 // so that we can find a more appropriate descriptor in for the
490 // given name
491 _unmarshalHandler.getNamespaceHandling().createNamespace();
492 _unmarshalHandler.startElementProcessing(name, namespace, atts);
493 return;
494 }
495 // --End of the container support
496
497 // -- Find object type and create new Object of that type
498 state.setFieldDescriptor(descriptor);
499
500 /*
501 * <update> we need to add this code back in, to make sure we have
502 * proper access rights.
503 *
504 * if (!descriptor.getAccessRights().isWritable()) { if (debug) {
505 * buf.setLength(0); buf.append("The field for element '");
506 * buf.append(name); buf.append("' is read-only.");
507 * message(buf.toString()); } return; }
508 */
509
510 // -- Find class to instantiate
511 // -- check xml names to see if we should look for a more specific
512 // -- ClassDescriptor, otherwise just use the one found in the
513 // -- descriptor
514 classDesc = null;
515 if (cdInherited != null)
516 classDesc = cdInherited;
517 else if (!name.equals(descriptor.getXMLName()))
518 classDesc = _unmarshalHandler.resolveByXMLName(name, namespace,
519 null);
520
521 if (classDesc == null)
522 classDesc = (XMLClassDescriptor) descriptor.getClassDescriptor();
523 FieldHandler handler = descriptor.getHandler();
524 boolean useHandler = true;
525
526 try {
527
528 // -- Get Class type...first use ClassDescriptor,
529 // -- since it could be more specific than
530 // -- the FieldDescriptor
531 if (classDesc != null) {
532 cls = classDesc.getJavaClass();
533
534 // -- XXXX This is a hack I know...but we
535 // -- XXXX can't use the handler if the field
536 // -- XXXX types are different
537 if (descriptor.getFieldType() != cls) {
538 state.setDerived(true);
539 }
540 } else {
541 cls = descriptor.getFieldType();
542 }
543
544 // -- This *shouldn't* happen, but a custom implementation
545 // -- could return null in the XMLClassDesctiptor#getJavaClass
546 // -- or XMLFieldDescriptor#getFieldType. If so, just replace
547 // -- with java.lang.Object.class (basically "anyType").
548 if (cls == null) {
549 cls = java.lang.Object.class;
550 }
551
552 // Retrieving the xsi:type attribute, if present
553 String currentPackage = _unmarshalHandler
554 .getJavaPackage(parentState.getType());
555 String instanceType = _unmarshalHandler.getInstanceType(atts,
556 currentPackage);
557 if (instanceType != null) {
558
559 Class instanceClass = null;
560 try {
561
562 XMLClassDescriptor instanceDesc = _unmarshalHandler
563 .getClassDescriptor(instanceType,
564 _unmarshalHandler.getClassLoader());
565
566 boolean loadClass = true;
567
568 if (instanceDesc != null) {
569 instanceClass = instanceDesc.getJavaClass();
570 classDesc = instanceDesc;
571 if (instanceClass != null) {
572 loadClass = (!instanceClass.getName().equals(
573 instanceType));
574 }
575 }
576
577 if (loadClass) {
578 instanceClass = _unmarshalHandler.loadClass(
579 instanceType, null);
580 // the FieldHandler can be either an XMLFieldHandler
581 // or a FieldHandlerImpl
582 FieldHandler tempHandler = descriptor.getHandler();
583
584 boolean collection = false;
585 if (tempHandler instanceof FieldHandlerImpl) {
586 collection = ((FieldHandlerImpl) tempHandler)
587 .isCollection();
588 } else {
589 collection = Introspector
590 .isCollection(instanceClass);
591 }
592
593 if ((!collection)
594 && !cls.isAssignableFrom(instanceClass)) {
595 if (!MarshalFramework.isPrimitive(cls)) {
596 String err = MessageFormat
597 .format(resourceBundle
598 .getString("unmarshalHandler.error.not.subclass"),
599 new Object[] {
600 instanceClass.getName(),
601 cls.getName() });
602 throw new SAXException(err);
603 }
604 }
605 }
606 cls = instanceClass;
607 useHandler = false;
608 } catch (Exception ex) {
609 String err = MessageFormat
610 .format(resourceBundle
611 .getString("unmarshalHandler.error.unable.instantiate.exception"),
612 new Object[] { instanceType,
613 ex.getMessage() });
614 throw new SAXException(err, ex);
615 }
616
617 }
618
619 // -- Handle ArrayHandler
620 if (cls == Object.class) {
621 if (parentState.getObject() instanceof ArrayHandler)
622 cls = ((ArrayHandler) parentState.getObject()).componentType();
623 }
624
625 // -- Handle support for "Any" type
626
627 if (cls == Object.class) {
628 Class pClass = parentState.getType();
629 ClassLoader loader = pClass.getClassLoader();
630 // -- first look for a descriptor based
631 // -- on the XML name
632 classDesc = _unmarshalHandler.resolveByXMLName(name, namespace,
633 loader);
634 // -- if null, create classname, and try resolving
635 String cname = null;
636 if (classDesc == null) {
637 // -- create class name
638 cname = _unmarshalHandler.getJavaNaming().toJavaClassName(
639 name);
640 classDesc = _unmarshalHandler.getClassDescriptor(cname,
641 loader);
642 }
643 // -- if still null, try using parents package
644 if (classDesc == null) {
645 // -- use parent to get package information
646 String pkg = pClass.getName();
647 int idx = pkg.lastIndexOf('.');
648 if (idx > 0) {
649 pkg = pkg.substring(0, idx + 1);
650 cname = pkg + cname;
651 classDesc = _unmarshalHandler.getClassDescriptor(cname,
652 loader);
653 }
654 }
655
656 if (classDesc != null) {
657 cls = classDesc.getJavaClass();
658 useHandler = false;
659 } else {
660 // we are dealing with an AnyNode
661 state.setObject(_unmarshalHandler.getAnyNodeHandler()
662 .commonStartElement(name, namespace,
663 state.isWhitespacePreserving()));
664 state.setType(cls);
665 return;
666 }
667 }
668
669 boolean byteArray = false;
670 if (cls.isArray())
671 byteArray = (cls.getComponentType() == Byte.TYPE);
672
673 // -- check for immutable
674 if (MarshalFramework.isPrimitive(cls) || descriptor.isImmutable()
675 || byteArray) {
676 state.setObject(null);
677 state.setPrimitiveOrImmutable(true);
678 // -- handle immutable types, such as java.util.Locale
679 if (descriptor.isImmutable()) {
680 if (classDesc == null)
681 classDesc = _unmarshalHandler.getClassDescriptor(cls);
682 state.setClassDescriptor(classDesc);
683 Arguments args = _unmarshalHandler.processConstructorArgs(
684 atts, classDesc);
685 if ((args != null) && (args.size() > 0)) {
686 state.setConstructorArguments(args);
687 }
688 }
689 } else {
690 if (classDesc == null)
691 classDesc = _unmarshalHandler.getClassDescriptor(cls);
692
693 // -- XXXX should remove this test once we can
694 // -- XXXX come up with a better solution
695 if ((!state.isDerived()) && useHandler) {
696
697 boolean create = true;
698 if (_unmarshalHandler.isReuseObjects()) {
699 state.setObject(handler.getValue(parentState.getObject()));
700 create = (state.getObject() == null);
701 }
702 if (create) {
703 Arguments args = _unmarshalHandler
704 .processConstructorArgs(atts, classDesc);
705 if ((args.getValues() != null) && (args.getValues().length > 0)) {
706 if (handler instanceof ExtendedFieldHandler) {
707 ExtendedFieldHandler efh = (ExtendedFieldHandler) handler;
708 state.setObject(efh.newInstance(
709 parentState.getObject(), args.getValues()));
710 } else {
711 String err = resourceBundle
712 .getString("unmarshalHandler.error.constructor.arguments");
713 throw new SAXException(err);
714 }
715 } else {
716 state.setObject(handler
717 .newInstance(parentState.getObject()));
718 }
719 }
720 }
721 // -- reassign class in case there is a conflict
722 // -- between descriptor#getFieldType and
723 // -- handler#newInstance...I should hope not, but
724 // -- who knows
725 if (state.getObject() != null) {
726 cls = state.getObject().getClass();
727 if (classDesc != null) {
728 if (classDesc.getJavaClass() != cls) {
729 classDesc = null;
730 }
731 }
732 } else {
733 try {
734 if (cls.isArray()) {
735 state.setObject(new ArrayHandler(
736 cls.getComponentType()));
737 cls = ArrayHandler.class;
738 } else {
739 Arguments args = _unmarshalHandler
740 .processConstructorArgs(atts, classDesc);
741 state.setObject(_unmarshalHandler.createInstance(
742 cls, args));
743 // state.object = _class.newInstance();
744 }
745 } catch (java.lang.Exception ex) {
746 String err = MessageFormat
747 .format(resourceBundle
748 .getString("unmarshalHandler.error.unable.instantiate.exception"),
749 new Object[] {
750 _unmarshalHandler
751 .className(cls),
752 ex.getMessage() });
753 throw new SAXException(err, ex);
754 }
755 }
756 }
757 state.setType(cls);
758 } catch (java.lang.IllegalStateException ise) {
759 LOG.error(ise.toString());
760 throw new SAXException(ise);
761 }
762
763 // -- At this point we should have a new object, unless
764 // -- we are dealing with a primitive type, or a special
765 // -- case such as byte[]
766 if (classDesc == null) {
767 classDesc = _unmarshalHandler.getClassDescriptor(cls);
768 }
769 state.setClassDescriptor(classDesc);
770
771 if ((state.getObject() == null) && (!state.isPrimitiveOrImmutable())) {
772 String err = MessageFormat.format(resourceBundle
773 .getString("unmarshalHandler.error.unable.unmarshal"),
774 new Object[] { name, _unmarshalHandler.className(cls) });
775 throw new SAXException(err);
776 }
777
778 // -- assign object, if incremental
779
780 if (descriptor.isIncremental()) {
781 if (LOG.isDebugEnabled()) {
782 String debug = MessageFormat.format(resourceBundle
783 .getString("unmarshalHandler.log.debug.process.incrementally"),
784 new Object[] { name });
785 LOG.debug(debug);
786 }
787 try {
788 handler.setValue(parentState.getObject(), state.getObject());
789 } catch (java.lang.IllegalStateException ise) {
790 String err = MessageFormat
791 .format(resourceBundle
792 .getString("unmarshalHandler.error.unable.add.element"),
793 new Object[] { name,
794 parentState.getFieldDescriptor().getXMLName(),
795 ise.getMessage() });
796 throw new SAXException(err, ise);
797 }
798 }
799
800 if (state.getObject() != null) {
801 // --The object has just been initialized
802 // --notify the listener
803 Object stateObject = state.getObject();
804 Object parentObject = (state.getParent() == null) ? null
805 : state.getParent().getObject();
806 _unmarshalHandler.getDelegateUnmarshalListener().initialized(
807 stateObject, parentObject);
808 _unmarshalHandler.processAttributes(atts, classDesc);
809 _unmarshalHandler.getDelegateUnmarshalListener().attributesProcessed(
810 stateObject, parentObject);
811 _unmarshalHandler.getNamespaceHandling().processNamespaces(classDesc,
812 _unmarshalHandler.getStateStack().getLastState().getObject());
813 } else if ((state.getType() != null) && (!state.isPrimitiveOrImmutable())) {
814 if (atts != null) {
815 _unmarshalHandler.processWrapperAttributes(atts);
816 String warn = MessageFormat.format(resourceBundle
817 .getString("unmarshalHandler.log.warn.process.attribute.as.location"),
818 new Object[] { name });
819 LOG.warn(warn);
820 }
821 } else {
822 // -- check for special attributes, such as xsi:nil
823 if (atts != null) {
824 String nil = atts.getValue(MarshalFramework.NIL_ATTR,
825 MarshalFramework.XSI_NAMESPACE);
826 state.setNil("true".equals(nil));
827 _unmarshalHandler.processWrapperAttributes(atts);
828 }
829 }
830 }
831
832 }