プロジェクトアドレス:activiti-ワークフロー
CCのタグをユーザーノード拡張子に追加すると、org.xml.sax.SAXParseExceptionがbpmnファイルインポートプロセスを通じて報告されます。要素「userTask」が名前空間「http:// activiti」にバインドされるように指定されています。 .org / bpmn "属性" XXXX。 "
bebuggerfを通じて、特定のエラーがXMLNSDocumentScannerImplクラスに表示されることが判明しました。
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);
}
}
}
checkDuplicatesNSメソッドを見てください
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();
}
}
間違ったオブジェクト情報を投稿する
同じタグが2つ存在しないと言っても過言ではありませんが、設定を繰り返すことはできますか?コードを注意深く確認したところ、重複する設定は見つかりませんでした。
独自の拡張機能のコード。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);
}
この時点で、activitiのソースコードが別の属性を設定していると結論付けることができます。Activitiは、BaseBpmnXMLConverter#convertToXMLからbpmnファイルを解析します。
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();
}
このメソッドには設定コードが見つかりませんでした。サブカテゴリのみが表示されます。上記のCustomUserTaskXMLConverterのwriteAdditionalAttributesメソッドに注意してください
BpmnXMLUtil.writeCustomAttributes(userTask.getAttributes().values(), xtw, defaultElementAttributes,
defaultActivityAttributes, defaultUserTaskAttributes);
userTaskの属性属性はここでは設定されていません。空である必要がありますが、フォローアップしたところ、そうではなく、たまたまCCの属性であることがわかりました。ここであなたは理解するでしょう、別の設定がここにあります。
この時点で、属性がいつ設定されるかを決定するだけで済みます。BaseElement#addAttributeにブレークポイントを設定します。最後に、それがCustomUserTaskXMLConverter#convertXMLToElementメソッドであることがわかりました
@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メソッド、主に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);
}
}
}
何を見てみましょうisBlacklistedはありませんが
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;
}
ブラックリスト値
/**
* 用户节点默认通用属性
*/
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)
);
ここで設定した後、すべてOKをテストします。