1

org.eclipse.wst.wsdl.util.WSDLResourceImpl を使用して WSDL ファイルをロードしているときに問題が発生し、Nullpointer Exception の問題が見つかりました。

EMF モデルが 1 つのクラス ローダーで初期化され、2 番目のクラス ローダーが EMF WSDl ロードを呼び出すと、org.eclipse.wst.wsdl.internal.impl.MessageImpl の以下のコードが Nullpointer 例外を引き起こすことがわかりました。

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 = ((WSDLPackage)EPackage.Registry.INSTANCE.getEPackage(WSDLPackage.eNS_URI)).getWSDLFactory().createPart();

2 番目のクラスローダの WSDL 名前空間 URI のエントリがレジストリにないため

上記の問題のスタックトレースを以下に示します

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 モデルがクラスローダー 1 で初期化されるスレッドが 1 つあります。次に、モデル WSDL ファイルの読み込みを呼び出す別のスレッドがあり、そこでクラスローダー 2 が読み込みを行っています。次に、org.eclipse.wst.wsdl.internal.impl.MessageImpl の以下のコードは Nullpointer 例外で失敗します

パート part = ((WSDLPackage)EPackage.Registry.INSTANCE.getEPackage(WSDLPackage.eNS_URI)).getWSDLFactory().createPart();

したがって、2 回目の isInited が true であり、初期化が行われないため、2 回目の EMF クラスがロードされた場合、2 つのクラス ローダーでは EMF モデルを初期化できないことは明らかです。切り取ったコードを以下に示します

 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;
  }

org.eclipse.xsd.util.XSDResourceImpl を使用して XSD ファイルをロードすると、以下のメソッドになるため、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 で問題が発生します。

また、2つの疑問があります

1) レジストリがクラスローダごとである理由。その場合、EMF が一度初期化されると、複数のクラスローダーのレジストリにデータを入力する方法があり、再度初期化することはできません。

2) org.eclipse.wst.wsdl.internal.impl.MessageImpl でも、レジストリの代わりに WSDFactory.eINSTANCE を使用できない理由

これは、私たちが取り組んでいるプロジェクトの 1 つにとって非常に重要であるため、お知らせください。非常に優先度の高いソリューションが必要です

ありがとうございます

4

0 に答える 0