Content-Type设为application/xml时出现Class Mediation错误求助
问题分析:Class Mediator 中介处理报错
错误信息
ErrorCode = 0, ErrorMessage = Error occured in the mediation of the class mediator, ErrorDetail = org.apache.synapse.SynapseException: Error occured in the mediation of the class mediator
代理服务配置(消费端)
<?xml version="1.0" encoding="UTF-8"?> <proxy name="UnicaProvConsumer" startOnLoad="true" transports="jms" xmlns="http://ws.apache.org/ns/synapse"> <target> <inSequence> <sequence key="MainSequence"/> </inSequence> <outSequence/> <faultSequence> <sequence key="Hello"/> </faultSequence> </target> <parameter name="transport.jms.Destination">REQ</parameter> <parameter name="transport.jms.ContentType">application/xml</parameter> <parameter name="transport.jms.ConnectionFactory">Listener</parameter> </proxy>
说明:将
transport.jms.ContentType设置为**'text/xml'**时可正常运行
序列配置
<?xml version="1.0" encoding="UTF-8"?> <sequence name="UnicaProvMainSequence" trace="disable" xmlns="http://ws.apache.org/ns/synapse"> <class description="UnicaProvSenderMediator" name="com.safaricom.mediator.UnicaProvSenderMediator"/> </sequence>
补充:相关Java类代码
public class UnicaProvSenderMediator extends AbstractMediator implements ManagedLifecycle { private static final Logger logger = LogManager.getLogger(UnicaProvSenderMediator.class.getName()); private static final Logger Errorlogger = LogManager.getLogger(ErrorHandling.class.getName()); private static JDBCConnectionPool jdbcPool = new JDBCConnectionPool(Utility.getProperty(Constant.EAI_JDBC_DRIVER), Utility.getProperty(Constant.EAI_JDBC_STRING), Utility.getProperty(Constant.EAI_JDBC_USER_NAME), Utility.getProperty(Constant.EAI_JDBC_PASSWORD)); static { System.setProperty("httpclient.hostnameVerifier", "AllowAll"); } public boolean mediate(MessageContext context) { // TODO Implement your mediation logic here Connection connection = null; try { SOAPEnvelope envelope = context.getEnvelope(); OMElement provNode = (OMElement) envelope.getBody().getFirstChildWithName(new QName("prov")).detach(); String retryCount = (provNode.getFirstChildWithName(new QName("retryCount")) == null) ? null : provNode.getFirstChildWithName(new QName("retryCount")).getText(); if (retryCount == null) { provNode.addChild(createOMElement("retryCount", "0")); context.setProperty("retryCount", "0"); } else { provNode.getFirstChildWithName(new QName("retryCount")).detach(); provNode.addChild(createOMElement("retryCount", String.valueOf(Integer.parseInt(retryCount) + 1))); context.setProperty("retryCount", String.valueOf(Integer.parseInt(retryCount) + 1)); } String incomingTimestamp = (provNode.getFirstChildWithName(new QName("incomingTimestamp")) == null) ? null : provNode.getFirstChildWithName(new QName("incomingTimestamp")).getText(); if (incomingTimestamp == null) { provNode.addChild(createOMElement("incomingTimestamp", String.valueOf(System.currentTimeMillis()))); } else { provNode.getFirstChildWithName(new QName("incomingTimestamp")).detach(); provNode.addChild(createOMElement("incomingTimestamp", String.valueOf(System.currentTimeMillis()))); } envelope.getBody().addChild(provNode); context.setProperty("orgMessage", getPayloadText(context)); msisdn = Utility.formatMSISDN(msisdn); String provisioningType = (provNode.getFirstChildWithName(new QName("provisioningType")) == null) ? null : provNode.getFirstChildWithName(new QName("provisioningType")).getText(); context.setProperty("provisioningType", provisioningType); context.setProperty("msisdn", msisdn); logger.info("Incoming prov request|rowID:" + rowID + "|msisdn:" + msisdn + "|provisioningType:" + provisioningType); logger.debug("Incoming prov request|rowID:" + rowID + "|msisdn:" + msisdn + "|provisioningType:" + provisioningType + "|orgMessage:" + getPayloadText(context)); return true; } catch (Exception ex) { logger.error(ErrorHandling.getMessage(ex)); Errorlogger.error(ErrorHandling.getStackTrace(ex)); jdbcPool.releaseConnection(connection); handleException(ex.getClass().getName(), ex, context); } return false; } }
报错原因分析
- SOAP信封处理逻辑差异:当
Content-Type设为application/xml时,WSO2 ESB不会自动将消息包装为SOAP信封;而设为text/xml时,ESB会默认把消息封装成SOAP结构。 - 代码依赖SOAP结构:你的
UnicaProvSenderMediator类中直接调用context.getEnvelope()获取SOAP信封,然后操作envelope.getBody()下的prov节点。如果消息没有被封装为SOAP信封,context.getEnvelope()会返回null,或者envelope.getBody()中不存在预期的节点,直接调用getFirstChildWithName(new QName("prov"))会抛出空指针或节点不存在的异常,最终触发SynapseException。 - 变量未初始化问题:代码中
msisdn和rowID变量没有初始化逻辑,在msisdn = Utility.formatMSISDN(msisdn);和日志打印时直接使用,这也会导致空指针异常,尤其是当消息结构不符合预期时,这个问题会被触发。
解决建议
- 若要使用
application/xml作为Content-Type,需要在序列中先添加<envelope/>中介器,手动将XML消息封装为SOAP信封,确保context.getEnvelope()能获取到有效对象。 - 修复代码中未初始化的
msisdn和rowID变量,添加空值检查逻辑,避免空指针异常。 - 在操作OM节点前,先检查节点是否存在,比如在调用
detach()前判断getFirstChildWithName()的返回值是否为null。
内容的提问来源于stack exchange,提问作者Wajih Haider
相关产品推荐
相关产品推荐

