如何在同一个Spring服务中实现多个SFDC出站消息接收者?

时间:2016-09-06 09:57:28

标签: spring-boot wsdl salesforce jax-ws spring-ws

对于每个出站消息,Salesforce提供完整的自包含WSDL。

为单个实现Spring服务很简单,使用jaxws-maven-plugin生成类,@Endpoint@PayloadRoot等来绑定端点。

但是,对于不同的结构和类型层次结构,多个出站消息都共享相同的QN(例如http://soap.sforce.com/2005/09/outbound:notificationsurn:sobject.enterprise.soap.sforce.com:sObject)。

我知道how to map the same XML names to different handlers based on URL path

我知道如何使用绑定文件为生成的类使用单独的包:

<?xml version="1.0" encoding="UTF-8"?>
<jaxws:bindings
    xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    wsdlLocation="../wsdl/SFDC_Contact_Outbound_Msg.wsdl"
    version="2.0">

  <jaxb:bindings node="//xs:schema[@targetNamespace='http://soap.sforce.com/2005/09/outbound']">
    <jaxb:schemaBindings>
      <jaxb:package name="com.sforce.soap.outbound.contact"/>
    </jaxb:schemaBindings>
  </jaxb:bindings>

  <jaxb:bindings node="//xs:schema[@targetNamespace='urn:sobject.enterprise.soap.sforce.com']">
    <jaxb:schemaBindings>
      <jaxb:package name="com.sforce.soap.enterprise.sobject.contact"/>
    </jaxb:schemaBindings>
  </jaxb:bindings>

</jaxws:bindings>

但是,当尝试从生成的代码初始化Jaxb2Marshaller时,它仍然无法处理XML冲突:

[WARN] [main] 09:40:45.687 AnnotationConfigEmbeddedWebApplicationContext - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException:
  Error creating bean with name 'marshaller' defined in class path resource [WebServiceConfig.class]: 
  Invocation of init method failed; nested exception is org.springframework.oxm.UncategorizedMappingException:
  Unknown JAXB exception; nested exception is com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 6 counts of IllegalAnnotationExceptions
  Two classes have the same XML type name "{urn:sobject.enterprise.soap.sforce.com}sObject". Use @XmlType.name and @XmlType.namespace to assign different names to them.
  ...

当SDFC生成的WSDL发生更改时,我不想再添加任何手动步骤,除了删除新文件。

有没有办法在不更改源WSDL的情况下更改package-info.java中的命名空间?

有没有办法轻松(即不为每个方法使用单独的@Bean方法)为每个包创建一个单独的编组器,然后可以将其添加到DefaultMethodEndpointAdapter

是否有其他方法可以实现所有这些出站消息接收器?

1 个答案:

答案 0 :(得分:0)

  

有没有办法更改命名空间?

如果你这样做,他们就不会匹配实际消息中的命名空间,所以它不会是无编组的。

  

有没有办法轻松为每个包创建一个单独的编组器?

嗯,这是 的方法。

@PostConstruct
public void marshallers() throws IOException {
  List<String> types = Arrays.stream(applicationContext.getResources("classpath:com/sforce/soap/outbound/*"))
      .map(Resource::getFilename)
      .collect(Collectors.toList());

  for (String type : types) {
    String beanName = "marshallingPayloadMethodProcessor_" + type;
    Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
    marshaller.setPackagesToScan(
        "com.sforce.soap.outbound." + type,
        "com.sforce.soap.enterprise.sobject." + type
    );

    try {
      marshaller.afterPropertiesSet();
    } catch (Exception ex) {
      throw new BeanInitializationException("Could not initialize bean " + beanName, ex);
    }

    MarshallingPayloadMethodProcessor processor = new MarshallingPayloadMethodProcessor(marshaller);
    beanFactory.registerSingleton(beanName, processor);
  }

有几点需要注意:

  • 如果通过jar进行部署,则类路径目录不存在,因此需要另一种方法来获取程序包名称。
  • registerSingleton似乎打破了某些应用程序上下文 - 导致无法再找到无关的bean。我不知道为什么会这样。