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