/** Receive notification of the end of an element. */ @Override public void endElement(String uri, String l, String q) { /* * 1. If current element is a String, update its value from the string buffer. * 2. Add the element to parent. */ ElementInfo element = _stack.remove(_stack.size() - 1); _logger.fine("endElement " + element); if (element.type == null) { _logger.warning("Element " + element.name + " not created "); return; } else if (_chars.length() > 0) { try { injectProperty(element.data, String.class, _chars.toString(), null, null); } catch (Exception x) { if (!_lenient) { throw new BeanAssemblyException( "Failed to set characters to object " + element.type.getName(), x); } else { _logger.warning("Failed to set characters to parent " + element.data); } } } _chars.setLength(0); _logger.fine( "<<ElementInfo: " + element.type.getName() + " in " + element + "\n @as is " + element.inst.get("@as") + "\n @id is " + element.inst.get("@id")); if (List.class.isAssignableFrom(element.data.getClass()) && element.name.endsWith("...")) { List<?> list = (List<?>) element.data; Object array = Array.newInstance(element.type, list.size()); for (int i = 0; i < list.size(); ++i) { Array.set(array, i, list.get(i)); } element.data = array; } String id = element.inst.get("@id"); if (id != null) { // locally stored object - not added to the parent _local.put(id, element); } else if (!_stack.isEmpty()) { // inject into the parent as a property ElementInfo parent = _stack.get(_stack.size() - 1); _logger.fine("Parent is " + parent.data.getClass().getName()); try { String as = element.inst.get("@as"); if (as != null) { injectProperty( parent.data, element.type, element.data, Strings.toCamelCase(as, '-', false), element.args.complete()); } else { injectProperty(parent.data, element.type, element.data, null, element.args.complete()); } } catch (Exception x) { if (!_lenient) { throw new BeanAssemblyException( "Failed to set value " + element.data + " to parent " + parent.data, x); } else { _logger.log( Level.WARNING, "Failed to set value " + element.data + " to parent " + parent.data, x); } } } _top = element.data; }
/** Receive notification of the start of an element. */ @Override public void startElement(String uri, String l, String q, Attributes a) { /* * 1. Load a class that matches the element name. * 2. If no class found, assume the element maps to a String. * 3. Otherwise, construct a new object of the class with element attributes. */ _logger.fine( S.fine(_logger) ? "Consider element " + l + "\n uri " + uri + "\n q " + q : null); ElementInfo info = new ElementInfo(); // Record java packages defined on this element as xmlns for (int i = 0; i < a.getLength(); ++i) { _logger.fine( S.fine(_logger) ? " attr " + a.getQName(i) + "=" + a.getValue(i) + "\n " + a.getQName(i) + ":" + a.getURI(i) : null); if (a.getQName(i).startsWith("xmlns:") && a.getValue(i).startsWith("java://")) { info.pkgs.put(a.getQName(i).substring(6), a.getValue(i).substring(7)); } } // Resolve the package name of this element, which could be empty (default package) int colon = q.indexOf(':'); if (colon > 0) { String xmlns = q.substring(0, colon); // is it defined right here? info.jpkg = info.pkgs.get(xmlns); // find a matching namespace from ancesters if (info.jpkg == null && !_stack.isEmpty()) { for (int i = _stack.size() - 1; i >= 0; --i) { info.jpkg = _stack.get(i).pkgs.get(xmlns); if (info.jpkg != null) { break; } } } } else if (isPrimitiveType(q)) { info.jpkg = "java.lang"; } else if (!_stack.isEmpty()) { info.jpkg = _stack.get(_stack.size() - 1).jpkg; } else { info.jpkg = _jpkg; } _logger.fine("to create element with package = " + info.jpkg); try { info.name = (info.jpkg != null) ? info.jpkg + '.' + Strings.toCamelCase(l) : Strings.toCamelCase(l); try { if (info.name.endsWith("...")) { // Array construction info.type = Class.forName(info.name.substring(0, info.name.length() - 3)); info.data = new ArrayList<Object>(); } else { // Non-array construction int size = a.getLength(); TypedValueGroup arguments = new TypedValueGroup(); for (int i = 0; i < size; ++i) { if (!a.getQName(i).startsWith("xmlns:") && !a.getQName(i).equals("xmlns")) { arguments.add(guessUntypedValue(a.getQName(i), a.getValue(i))); } } arguments.complete(); _logger.fine(S.fine(_logger) ? "arguments=" + arguments : null); if (arguments.size() > 0) { if (arguments.size() == 1 && "java.lang".equals(info.jpkg)) { info.inst.put( "@as", Strings.toCamelCase( arguments.get(0).name, '-', false)); // respect original spelling info.data = arguments.get(0).get(0).data; info.type = arguments.get(0).get(0).type; } else { Exception last = null; Object[] args = new Object[arguments.size()]; while (arguments.load(args, 0)) { try { _logger.fine( S.fine(_logger) ? "to create " + info.name + " with args: " + args.length + args(args) : null); info.data = _factory.create(info.name, args); info.type = info.data.getClass(); break; } catch (InvocationTargetException x) { throw x; } catch (Exception x) { last = x; _logger.fine( "failure in creating " + info.name + ": probing for other constructors"); } } if (info.data == null) { throw last; } } } else { _logger.fine("Create " + info.name + " with the default constructor"); info.data = _factory.create(info.name); info.type = info.data.getClass(); } } } catch (ClassNotFoundException x) { // no class by the element name is found, assumed String if (!_lenient) { throw new BeanAssemblyException("No class associated with element " + q); } else { _logger.log(Level.WARNING, "can't find class " + info.name, x); } } _stack.add(info); // _logger.fine(">>ElementInfo: " + info.type.getName() + " in " + info); // all other exceptions indicate mismatches between the beans and the XML schema } catch (Exception x) { if (!_lenient) { throw new BeanAssemblyException("Failed to assemble bean from element " + q, x); } else { _logger.log(Level.SEVERE, "can't create object for this element", x); } } }