Activiti custom BPMN tag report: org.xml.sax.SAXParseException: The element userTask has been bound to the namespace http://activiti.org/bpmn

Project address: activiti-workflow

When adding the tag of the CC to the user node extension, the org.xml.sax.SAXParseException is reported through the bpmn file import process: the element "userTask" has been specified to be bound to the namespace "http://activiti.org/bpmn" Attribute "XXXX."

Through bebuggerf, it was found that the specific error appeared in the XMLNSDocumentScannerImpl class

 if (length > 1) {
    
    
 		//对元素进行校验name不为空说明有重复元素
	   QName name = fAttributes.checkDuplicatesNS();
       if (name != null) {
    
    
           if (name.uri != null) {
    
    
               fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
                       "AttributeNSNotUnique",
                       new Object[]{
    
    fElementQName.rawname, name.localpart, name.uri},
                       XMLErrorReporter.SEVERITY_FATAL_ERROR);
           } else {
    
    
               fErrorReporter.reportError(XMLMessageFormatter.XMLNS_DOMAIN,
                       "AttributeNotUnique",
                       new Object[]{
    
    fElementQName.rawname, name.rawname},
                       XMLErrorReporter.SEVERITY_FATAL_ERROR);
           }
       }
   }

Looking at the checkDuplicatesNS method

    public QName checkDuplicatesNS() {
    
    
        // If the list is small check for duplicates using pairwise comparison.
        final int length = fLength;
        if (length <= SIZE_LIMIT) {
    
    
            final Attribute[] attributes = fAttributes;
            for (int i = 0; i < length - 1; ++i) {
    
    
                Attribute att1 = attributes[i];
                for (int j = i + 1; j < length; ++j) {
    
    
                    Attribute att2 = attributes[j];
                    //只有当标签名称和命名空间一样时有返回
                    if (att1.name.localpart == att2.name.localpart &&
                        att1.name.uri == att2.name.uri) {
    
    
                        return att2.name;
                    }
                }
            }
            return null;
        }
        // If the list is large check duplicates using a hash table.
        else {
    
    
            return checkManyDuplicatesNS();
        }
    }

Posting the wrong object information It is
Insert picture description here
reasonable to say that there will not be two identical tags. Could it be repeated settings? After carefully checking the code, no duplicate settings were found.
The code of own extension, only this attribute set in CustomUserTaskXMLConverter

@Override
  @SuppressWarnings("unchecked")
  protected void writeAdditionalAttributes(BaseElement element, BpmnModel model, XMLStreamWriter xtw) throws Exception {
    
    
	//省略部分代码
    //设置抄送标签属性
    writeQualifiedAttribute(ATTRIBUTE_TASK_USER_CANDIDATE_NOTIFY_USERS, convertToDelimitedString(userTask.getCandidateNotifyUsers()), xtw);
   	//省略部分代码
    // 注意,注意,注意
    BpmnXMLUtil.writeCustomAttributes(userTask.getAttributes().values(), xtw, defaultElementAttributes,
        defaultActivityAttributes, defaultUserTaskAttributes);
  }

At this point, it can be concluded that the source code of activiti has set another attribute. Activiti parses the bpmn file from BaseBpmnXMLConverter#convertToXML,

public void convertToXML(XMLStreamWriter xtw, BaseElement baseElement, BpmnModel model) throws Exception {
    
    
    xtw.writeStartElement(getXMLElementName());
    boolean didWriteExtensionStartElement = false;
    writeDefaultAttribute(ATTRIBUTE_ID, baseElement.getId(), xtw);
    if (baseElement instanceof FlowElement) {
    
    
      writeDefaultAttribute(ATTRIBUTE_NAME, ((FlowElement) baseElement).getName(), xtw);
    }
    
    if (baseElement instanceof FlowNode) {
    
    
      final FlowNode flowNode = (FlowNode) baseElement;
      if (flowNode.isAsynchronous()) {
    
    
        writeQualifiedAttribute(ATTRIBUTE_ACTIVITY_ASYNCHRONOUS, ATTRIBUTE_VALUE_TRUE, xtw);
        if (flowNode.isNotExclusive()) {
    
    
          writeQualifiedAttribute(ATTRIBUTE_ACTIVITY_EXCLUSIVE, ATTRIBUTE_VALUE_FALSE, xtw);
        }
      }
      
      if (baseElement instanceof Activity) {
    
    
        final Activity activity = (Activity) baseElement;
        if (activity.isForCompensation()) {
    
    
          writeDefaultAttribute(ATTRIBUTE_ACTIVITY_ISFORCOMPENSATION, ATTRIBUTE_VALUE_TRUE, xtw);
        }
        if (StringUtils.isNotEmpty(activity.getDefaultFlow())) {
    
    
          FlowElement defaultFlowElement = model.getFlowElement(activity.getDefaultFlow());
          if (defaultFlowElement instanceof SequenceFlow) {
    
    
            writeDefaultAttribute(ATTRIBUTE_DEFAULT, activity.getDefaultFlow(), xtw);
          }
        }
      }
      
      if (baseElement instanceof Gateway) {
    
    
        final Gateway gateway = (Gateway) baseElement;
        if (StringUtils.isNotEmpty(gateway.getDefaultFlow())) {
    
    
          FlowElement defaultFlowElement = model.getFlowElement(gateway.getDefaultFlow());
          if (defaultFlowElement instanceof SequenceFlow) {
    
    
            writeDefaultAttribute(ATTRIBUTE_DEFAULT, gateway.getDefaultFlow(), xtw);
          }
        }
      }
    }
	//具体子类执行
    writeAdditionalAttributes(baseElement, model, xtw);

    if (baseElement instanceof FlowElement) {
    
    
      final FlowElement flowElement = (FlowElement) baseElement;
      if (StringUtils.isNotEmpty(flowElement.getDocumentation())) {
    
    

        xtw.writeStartElement(ELEMENT_DOCUMENTATION);
        xtw.writeCharacters(flowElement.getDocumentation());
        xtw.writeEndElement();
      }
    }

    didWriteExtensionStartElement = writeExtensionChildElements(baseElement, didWriteExtensionStartElement, xtw);
    didWriteExtensionStartElement = writeListeners(baseElement, didWriteExtensionStartElement, xtw);
    didWriteExtensionStartElement = BpmnXMLUtil.writeExtensionElements(baseElement, didWriteExtensionStartElement, model.getNamespaces(), xtw);
    if (baseElement instanceof Activity) {
    
    
      final Activity activity = (Activity) baseElement;
      FailedJobRetryCountExport.writeFailedJobRetryCount(activity, xtw);

    }

    if (didWriteExtensionStartElement) {
    
    
      xtw.writeEndElement();
    }

    if (baseElement instanceof Activity) {
    
    
      final Activity activity = (Activity) baseElement;
      MultiInstanceExport.writeMultiInstance(activity, xtw);

    }

    writeAdditionalChildElements(baseElement, model, xtw);

    xtw.writeEndElement();
  }

No setting code was found in this method, only the sub-categories can be seen. Pay attention to the writeAdditionalAttributes method of CustomUserTaskXMLConverter above

 BpmnXMLUtil.writeCustomAttributes(userTask.getAttributes().values(), xtw, defaultElementAttributes,
        defaultActivityAttributes, defaultUserTaskAttributes);

The attributes attribute of userTask is not set here, it should be empty, but I just followed up and found that it was not, it happened to be the attribute of CC. Here you will understand, another setting is here.
Insert picture description here

At this point, you only need to determine when the attributes are set. Set a breakpoint in BaseElement#addAttribute . Finally found that it is the CustomUserTaskXMLConverter#convertXMLToElement method

@Override
  protected BaseElement convertXMLToElement(XMLStreamReader xtr, BpmnModel model) throws Exception {
    
    
   	//省略部分代码
   	//设置Attributes属性
    BpmnXMLUtil.addCustomAttributes(xtr, userTask, defaultElementAttributes,
        defaultActivityAttributes, defaultUserTaskAttributes);

    parseChildElements(getXMLElementName(), userTask, childParserMap, model, xtr);
    
    return userTask;
  }

BpmnXMLUtil.addCustomAttributes method, mainly in isBlacklisted

public static void addCustomAttributes(XMLStreamReader xtr, BaseElement element, List<ExtensionAttribute>... blackLists) {
    
    
	//迭代出各个属性判断是否有命名空间,是否是自定义属性
    for (int i = 0; i < xtr.getAttributeCount(); i++) {
    
    
      ExtensionAttribute extensionAttribute = new ExtensionAttribute();
      extensionAttribute.setName(xtr.getAttributeLocalName(i));
      extensionAttribute.setValue(xtr.getAttributeValue(i));
      if (StringUtils.isNotEmpty(xtr.getAttributeNamespace(i))) {
    
    
        extensionAttribute.setNamespace(xtr.getAttributeNamespace(i));
      }
      if (StringUtils.isNotEmpty(xtr.getAttributePrefix(i))) {
    
    
        extensionAttribute.setNamespacePrefix(xtr.getAttributePrefix(i));
      }
      if (!isBlacklisted(extensionAttribute, blackLists)) {
    
    
        element.addAttribute(extensionAttribute);
      }
    }
  }

Take a look at what isBlacklisted does

 public static boolean isBlacklisted(ExtensionAttribute attribute, List<ExtensionAttribute>... blackLists) {
    
    
    if (blackLists != null) {
    
    
      for (List<ExtensionAttribute> blackList : blackLists) {
    
    
        for (ExtensionAttribute blackAttribute : blackList) {
    
    
        	//是否是默认属性
          if (blackAttribute.getName().equals(attribute.getName())) {
    
    
          //命名空间是否一样
            if (blackAttribute.getNamespace() != null && attribute.getNamespace() != null && blackAttribute.getNamespace().equals(attribute.getNamespace()))
              return true;
            if (blackAttribute.getNamespace() == null && attribute.getNamespace() == null)
              return true;
          }
        }
      }
    }
    return false;
  }

blackList value

 /**
   * 用户节点默认通用属性
   */
  protected static final List<ExtensionAttribute> defaultUserTaskAttributes = Arrays.asList(
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_FORM_FORMKEY),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_DUEDATE),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_BUSINESS_CALENDAR_NAME),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_ASSIGNEE),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_OWNER),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_PRIORITY),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATEUSERS),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATEGROUPS),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CATEGORY),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_SERVICE_EXTENSIONID),
          //设置抄送为默认通用标签
          //new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_CANDIDATE_NOTIFY_USERS),
          new ExtensionAttribute(ACTIVITI_EXTENSIONS_NAMESPACE, ATTRIBUTE_TASK_USER_SKIP_EXPRESSION)
  );

Test everything OK after setting here.

Guess you like

Origin blog.csdn.net/qq_34758074/article/details/106356127