View Javadoc
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 }