JAX-RPC (JSR-101) 定義了 XML 到 Java 的標準類型映射,但對複雜 XML Schema(如未定義全域元素的區域元素)支援不足,會退化為 SOAPElement,導致開發者需手寫解析代碼。本文展示如何結合 EMF (Eclipse Modeling Framework),為無標準映射的 XML 類型生成強類型 Java 模型,並整合至 WebSphere Studio Application Developer 開發的 Web 服務中。
SupplyChainService.wsdlSupplyChainSchema.xsd,包含 PurchaseOrderType、PaymentMethodType、ShippingNoticeType 等複雜類型。paymentMethod、item x2) 無全域宣告,JAX-RPC 僅映射為 SOAPElement。右鍵 WSDL → Web Services → Generate Java bean skeleton,產生 SupplyChainBindingImpl.java 等骨架代碼。修正 Schema 複製路徑後通過驗證。

SupplyChainSchema.xsd。
supplychain 套件 → Finish → 開啟 EMF Generator Editor → 右鍵根節點 → Generate Model Code。SupplyChainEMF 專案加入 EAR 作為 Utility JAR,並設定 Web 專案依賴。
EMF_COMMON、EMF_ECORE、EMF_ECORE_XMI。
// 靜態初始化 EMF Package
static { SupplychainPackageImpl.init(); }
// 1. SOAPElement → DOM Element (WebSphere 專用 API)
public Element soapElement2DOMElement(SOAPElement soapElement) throws Exception {
return ((com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)soapElement).getAsDOM();
}
// 2. DOM Element → EMF Object (EObject)
public EObject domElement2EObject(Element e) throws ... {
DOMSource domSource = new DOMSource(e);
Transformer serializer = TransformerFactory.newInstance().newTransformer();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serializer.transform(domSource, new StreamResult(baos));
byte[] xmlBytes = baos.toByteArray();
URI uri = URI.createURI(SupplychainPackage.eNS_URI);
Resource res = new SupplychainResourceFactoryImpl().createResource(uri);
res.load(new ByteArrayInputStream(xmlBytes), null);
return res.getContents().isEmpty() ? null : (EObject)res.getContents().get(0);
}
// 3. EMF Object → DOM Element
public Element eObject2DOMElement(EObject eObject) throws ... {
URI uri = URI.createURI(SupplychainPackage.eNS_URI);
Resource res = new SupplychainResourceFactoryImpl().createResource(uri);
res.getContents().add(eObject);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
res.save(baos, null);
byte[] xmlBytes = baos.toByteArray();
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
.parse(new ByteArrayInputStream(xmlBytes));
return doc.getDocumentElement();
}
// 4. DOM Element → SOAPElement (WebSphere 專用 API)
public SOAPElement domElement2SOAPElement(Element e) throws SOAPException {
SOAPFactory factory = SOAPFactory.newInstance();
com.ibm.ws.webservices.engine.xmlsoap.SOAPElement soapEl =
(com.ibm.ws.webservices.engine.xmlsoap.SOAPElement)factory.createElement("temp");
soapEl.setAlternateContent(e);
return soapEl;
}
EMF 預設僅映射全域元素。需為區域元素手動註冊映射:
SupplychainPackageImpl.initializePackageContents() 尾部添加:initEClass(paymentMethodTypeEClass, PaymentMethodType.class, "paymentMethod", !IS_ABSTRACT, !IS_INTERFACE);SupplychainPackageImpl 添加四個方法:initPurchaseItem()/removePurchaseItem()、initShippingItem()/removeShippingItem(),分別為 PurchaseOrderType.item 與 ShippingNoticeType.item 建立/移除映射。
public PurchaseReferenceType submitPurchaseOrder(PurchaseOrderType purchaseOrder) {
try {
// 1. paymentMethod (靜態映射)
PaymentMethodType paymentMethod = (PaymentMethodType)
domElement2EObject(soapElement2DOMElement((SOAPElement)purchaseOrder.getPaymentMethod()));
// 2. item (動態映射 PurchaseOrderType.item)
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initPurchaseItem();
ItemType item = (ItemType)
domElement2EObject(soapElement2DOMElement((SOAPElement)purchaseOrder.getItem()));
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removePurchaseItem();
// 3. shippingNotice.item (動態映射 ShippingNoticeType.item)
ShippingNoticeType shippingNotice = purchaseOrder.getShippingNotice();
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).initShippingItem();
ShippingItemType shippingItem = (ShippingItemType)
domElement2EObject(soapElement2DOMElement((SOAPElement)shippingNotice.getItem()));
((SupplychainPackageImpl)SupplychainPackage.eINSTANCE).removeShippingItem();
// 業務計算...
PurchaseReferenceType ref = new PurchaseReferenceType();
ref.setReferenceNumber(String.valueOf(Math.abs(new Random().nextInt())));
// 回傳物體轉 SOAPElement
ref.setStatus(domElement2SOAPElement(eObject2DOMElement(status)));
return ref;
} catch (Throwable t) { t.printStackTrace(); return null; }
}
啟動測試環境 → 右鍵 WSDL → Test with Web Services Explorer → 輸入測試參數 → Go → 獲得正確回傳。

SOAPElement ⇄ DOM ⇄ EMF (EObject),利用 Transformer/Resource 序列化。