/* (non-Javadoc) * @see org.jibx.binding.model.ElementBase#validate(org.jibx.binding.model.ValidationContext) */ public void validate(ValidationContext vctx) { // call base class method first super.validate(vctx); // check for way to determine if named collection present on output if (vctx.isOutBinding() && hasName() && !hasProperty() && isOptional() && getTest() == null && !(vctx.getParentContainer() instanceof CollectionElement)) { vctx.addError("Need test method for optional collection output element"); } // make sure only named element components are present ArrayList children = children(); for (int i = 0; i < children.size(); i++) { IComponent child = (IComponent) children.get(i); if (child.hasAttribute()) { vctx.addFatal("Attributes not allowed as child components of collection", child); } } // check each child component if (m_itemTypeClass != null) { checkCollectionChildren(vctx, m_itemTypeClass, children); } // make sure child components can be distinguished if (children.size() > 1) { if (isOrdered()) { checkOrderedChildren(vctx, children); } else { checkUnorderedChildren(vctx, children); } } }
/** * Check children of unordered collection for consistency. In an input binding each child element * must define a unique qualified name. In an output binding each child element must define a * unique type or supply a test method to allow checking when that element should be generated for * an object. * * @param vctx validation context * @param children list of child components */ private void checkUnorderedChildren(ValidationContext vctx, ArrayList children) { HashMap typemap = new HashMap(); HashMap namemap = new HashMap(); for (int i = 0; i < children.size(); i++) { ElementBase child = (ElementBase) children.get(i); if (child instanceof IComponent && !vctx.isSkipped(child)) { IComponent comp = (IComponent) child; if (vctx.isInBinding()) { // make sure name supplied for unmarshalling if (!comp.hasName()) { vctx.addFatal( "Child components of collection must " + "define element name for unmarshalling", comp); } // names must be distinct in input binding String name = comp.getName(); String uri = comp.getUri(); if (uri == null) { uri = ""; } Object value = namemap.get(name); if (value == null) { // first instance of name, store directly namemap.put(name, comp); } else if (value instanceof HashMap) { // multiple instances already found, match on URI HashMap urimap = (HashMap) value; if (urimap.get(uri) != null) { vctx.addError("Duplicate names are not " + "allowed in unordered collection", comp); } else { urimap.put(uri, comp); } } else { // duplicate name, check URI IComponent match = (IComponent) value; if ((uri == null && match.getUri() == null) || (uri != null && uri.equals(match.getUri()))) { vctx.addError("Duplicate names are not " + "allowed in unordered collection", comp); } else { // multiple namespaces for same name, use map HashMap urimap = new HashMap(); urimap.put(uri, comp); String muri = match.getUri(); if (muri == null) { muri = ""; } urimap.put(muri, match); namemap.put(name, urimap); } } } if (vctx.isOutBinding()) { // just accumulate lists of each type in this loop String type = comp.getType().getName(); Object value = typemap.get(type); if (value == null) { typemap.put(type, comp); } else if (value instanceof ArrayList) { ArrayList types = (ArrayList) value; types.add(comp); } else { ArrayList types = new ArrayList(); types.add(value); types.add(comp); typemap.put(type, types); } } } } // check for duplicate type usage in output binding for (Iterator iter = typemap.values().iterator(); iter.hasNext(); ) { Object value = iter.next(); if (value instanceof ArrayList) { // multiple instances of type, make sure we can distinguish ArrayList types = (ArrayList) value; for (int i = 0; i < types.size(); i++) { Object child = types.get(i); if (child instanceof ValueElement) { ValueElement vel = (ValueElement) child; if (vel.getTest() == null) { vctx.addError( "test-method needed for " + "multiple instances of same type in " + "unordered collection", vel); } } else if (child instanceof StructureElementBase) { StructureElementBase sel = (StructureElementBase) child; if (sel.getTest() == null) { vctx.addError( "test-method needed for " + "multiple instances of same type in " + "unordered collection", sel); } } } } } }
/* (non-Javadoc) * @see org.jibx.binding.model.ElementBase#prevalidate(org.jibx.binding.model.ValidationContext) */ public void prevalidate(ValidationContext vctx) { // first process attributes and check for errors super.prevalidate(vctx); if (!vctx.isSkipped(this)) { // check for ignored attributes if (isAllowRepeats()) { vctx.addWarning("'allow-repeats' attribute ignored on collection"); } if (isChoice()) { vctx.addWarning("'choice' attribute ignored on collection"); } // get the actual collection type and item type IClass clas = getType(); if (clas == null) { clas = vctx.getContextObject().getObjectType(); } String tname = m_itemTypeName; if (tname == null) { String ctype = clas.getName(); if (ctype.endsWith("[]")) { tname = ctype.substring(0, ctype.length() - 2); } else { tname = "java.lang.Object"; } } m_itemTypeClass = vctx.getClassInfo(tname); if (m_itemTypeClass == null) { vctx.addFatal("Can't find class " + tname); } // handle input and output bindings separately if (vctx.isInBinding()) { // check store techniques String sname = m_storeMethodName; String aname = m_addMethodName; if (sname != null && aname != null) { vctx.addWarning("Both store-method and add-method " + "supplied; using add-method"); sname = null; } // set defaults based on collection type if needed if (sname == null && aname == null) { if (clas.isSuperclass("java.util.ArrayList") || clas.isSuperclass("java.util.Vector") || clas.isImplements("Ljava/util/Collection;")) { aname = "add"; } else if (!clas.getName().endsWith("[]")) { vctx.addError("Need store-method or add-method for " + "input binding"); } } // find the actual method information if (sname != null) { m_storeMethodItem = clas.getBestMethod(sname, null, new String[] {"int", tname}); if (m_storeMethodItem == null) { vctx.addError("store-method " + sname + " not found in class " + clas.getName()); } } if (aname != null) { m_addMethodItem = clas.getBestMethod(aname, null, new String[] {tname}); if (m_addMethodItem == null) { vctx.addError("add-method " + aname + " not found in class " + clas.getName()); } } } if (vctx.isOutBinding()) { // precheck load techniques String lname = m_loadMethodName; String sname = m_sizeMethodName; String iname = m_iterMethodName; if (lname == null) { if (sname != null) { vctx.addWarning("size-method requires load-method; " + "ignoring supplied size-method"); sname = null; } } else { if (sname == null) { vctx.addWarning("load-method requires " + "size-method; ignoring supplied load-method"); lname = null; } else { if (iname != null) { vctx.addWarning("Both load-method and " + "iter-method supplied; using load-method"); iname = null; } } } // set defaults based on collection type if needed if (lname == null && iname == null) { if (clas.isSuperclass("java.util.ArrayList") || clas.isSuperclass("java.util.Vector")) { lname = "get"; sname = "size"; } else if (clas.isImplements("Ljava/util/Collection;")) { iname = "iterator"; } } // postcheck load techniques with defaults set if (lname == null) { if (iname == null && !clas.getName().endsWith("[]")) { vctx.addError( "Need load-method and size-method, or " + "iter-method, for output binding"); } } else { if (sname == null && iname == null) { vctx.addError( "Need load-method and size-method," + " or iter-method, for output binding"); } } // find the actual method information if (lname != null) { m_loadMethodItem = clas.getBestMethod(lname, tname, new String[] {"int"}); if (m_loadMethodItem == null) { vctx.addError("load-method " + lname + " not found in class " + clas.getName()); } } if (iname != null) { m_iterMethodItem = clas.getBestMethod(iname, "java.util.Iterator", new String[0]); if (m_iterMethodItem == null) { vctx.addError("iter-method " + iname + " not found in class " + clas.getName()); } } } } }