当我们使用org.eclipse.wst.wsdl.util.WSDLResourceImpl加载WSDL文件时遇到问题,并且发现了Nullpointer异常的问题。
我们观察到,当在一个类加载器中初始化EMF模型并且第二个类加载器调用时,org.eclipse.wst.wsdl.internal.impl.MessageImpl中的以下代码会导致Nullpointer异常。 EMF WSDl加载。
public void handleUnreconciledElement(Element child, Collection remainingModelObjects)
{
switch (WSDLUtil.getInstance().getWSDLType(child))
{
case WSDLConstants.PART:
{
Part part = ((WSDLPackage)EPackage.Registry.INSTANCE.getEPackage(WSDLPackage.eNS_URI)).getWSDLFactory().createPart();
part.setEnclosingDefinition(getEnclosingDefinition());
part.setElement(child);
getEParts().add(part);
break;
}
default:
{
super.handleUnreconciledElement(child, remainingModelObjects);
break;
}
}
}
Nullpointer异常发生在这里
Part part =((WSDLPackage)EPackage.Registry.INSTANCE.getEPackage(WSDLPackage.eNS_URI))。getWSDLFactory()。createPart();
因为注册表没有第二个类加载器的WSDL名称空间URI的条目
以上问题的stackTrace如下所示
MessageImpl.handleUnreconciledElement(Element, Collection) line: 411
MessageImpl(WSDLElementImpl).reconcileContents(Element) line: 1296
MessageImpl(WSDLElementImpl).reconcile(Element) line: 1242
MessageImpl(WSDLElementImpl).changeAttribute(EAttribute) line: 1215
MessageImpl.changeAttribute(EAttribute) line: 467
MessageImpl(WSDLElementImpl).eNotify(Notification) line: 472
MessageImpl(WSDLElementImpl).setElementGen(Element) line: 181
MessageImpl(WSDLElementImpl).setElement(Element) line: 367
DefinitionImpl.handleUnreconciledElement(Element, Collection) line: 1785
DefinitionImpl(WSDLElementImpl).reconcileContents(Element) line: 1296
DefinitionImpl(WSDLElementImpl).reconcile(Element) line: 1242
DefinitionImpl(WSDLElementImpl).changeAttribute(EAttribute) line: 1215
DefinitionImpl.changeAttribute(EAttribute) line: 1997
DefinitionImpl(WSDLElementImpl).eNotify(Notification) line: 472
DefinitionImpl.eNotify(Notification) line: 515
DefinitionImpl(WSDLElementImpl).setElementGen(Element) line: 181
DefinitionImpl(WSDLElementImpl).setElement(Element) line: 367
DefinitionImpl.setElement(Element) line: 1704
DefinitionImpl.createDefinition(Node, String, boolean) line: 1511
WSDLResourceImpl.handleDefinitionElement(Element) line: 572
WSDLResourceImpl.findDefinition(Element) line: 540
WSDLResourceImpl.doLoad(InputSource, Map) line: 285
WSDLResourceImpl.doLoad(InputStream, Map) line: 358
WSDLResourceImpl(ResourceImpl).load(InputStream, Map<?,?>) line: 1505
我们拥有的场景是我们有一个线程,其中EMF WSDL模型使用Classloader 1初始化。接下来有另一个线程调用模型WSDL文件加载并在那里 Classloader 2正在进行加载。然后我们在org.eclipse.wst.wsdl.internal.impl.MessageImpl中的下面的代码失败,出现Nullpointer异常
Part part =((WSDLPackage)EPackage.Registry.INSTANCE.getEPackage(WSDLPackage.eNS_URI))。getWSDLFactory()。createPart();
很明显,对于两个类加载器,如果第一次加载EMF类,我们就无法初始化EMF模型,因为第二次isInited为true且初始化未完成。代码 snipped如下所示
public static WSDLPackage init()
{
if (isInited)
return (WSDLPackage)EPackage.Registry.INSTANCE.getEPackage(WSDLPackage.eNS_URI);
// Obtain or create and register package
WSDLPackageImpl theWSDLPackage = (WSDLPackageImpl)(EPackage.Registry.INSTANCE.getEPackage(eNS_URI) instanceof WSDLPackageImpl
? EPackage.Registry.INSTANCE.getEPackage(eNS_URI) : new WSDLPackageImpl());
isInited = true;
// Initialize simple dependencies
XSDPackage.eINSTANCE.eClass();
// Create package meta-data objects
theWSDLPackage.createPackageContents();
// Initialize created meta-data
theWSDLPackage.initializePackageContents();
// Mark meta-data to indicate it can't be changed
theWSDLPackage.freeze();
return theWSDLPackage;
}
现在XSD也出现同样的问题,因为当我们使用org.eclipse.xsd.util.XSDResourceImpl加载XSD文件时,它会转到下面的方法
XSDResourceImpl.handleSchemaElement(Element,boolean)
这里的代码如下所示
protected void handleSchemaElement(Element element, boolean isMeta)
{
XSDSchema xsdSchema;
if (element == null)
{
xsdSchema = XSDFactory.eINSTANCE.createXSDSchema();
xsdSchema.getQNamePrefixToNamespaceMap().put(null, XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001);
}
else if (isMeta)
{
xsdSchema = XSDSchemaImpl.createMetaSchema(element);
}
else
{
xsdSchema = XSDSchemaImpl.createSchema(element);
}
getContents().add(xsdSchema);
}
这里以流动方式使用XSDFcatory
xsdSchema = XSDFactory.eINSTANCE.createXSDSchema();
所以我们想知道为什么这个代码不能在org.eclipse.wst.wsdl.internal.impl.MessageImpl中更改,如下所示,这可以解决问题并且也与XSD行为一致
public void handleUnreconciledElement(Element child, Collection remainingModelObjects)
{
switch (WSDLUtil.getInstance().getWSDLType(child))
{
case WSDLConstants.PART:
{
Part part = WSDLFactory.eINSTANCE.createPart();
part.setEnclosingDefinition(getEnclosingDefinition());
part.setElement(child);
getEParts().add(part);
break;
}
default:
{
super.handleUnreconciledElement(child, remainingModelObjects);
break;
}
}
}
否则,如果此问题还有其他替代解决方案,请告诉我们。显然,当存在多个类加载器时,类加载会导致EPackage.Registry.INSTANCE出现问题。
我们还有两个疑问
1)为什么注册表是每个类加载器。如果是这种情况那么如何为多个类加载器填充注册表作为EMF一旦初始化它不允许再次初始化
2)同样在org.eclipse.wst.wsdl.internal.impl.MessageImpl中为什么不能使用WSDFactory.eINSTANCE而不是注册表
请告诉我们,因为这对我们正在开展的项目非常重要。我们需要具有非常高优先级的解决方案
谢谢和问候 Ananth