How to implement multiple SFDC Outbound Message receivers in the same Spring service?

为君一笑 提交于 2019-12-12 02:38:58

问题


For each Outbound Message, Salesforce provides a full self-contained WSDL.

Implementing a Spring service for a single one is easy, using jaxws-maven-plugin to generate the classes and @Endpoint, @PayloadRoot, etc to bind the endpoint.

However, multiple Outbound Messages all share the same QNs (for example http://soap.sforce.com/2005/09/outbound:notifications or urn:sobject.enterprise.soap.sforce.com:sObject) for different structures and type hierarchies.

I know how to map the same XML names to different handlers based on URL path.

I know how to use a separate package for the generated classes with a bindings file:

<?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>

However, when trying to initialise the Jaxb2Marshaller from the generated code, it still cannot handle the XML conflicts:

[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.
  ...

I do not want to add any more manual steps when the SDFC-generated WSDL changes, other than dropping in the new files.

Is there a way to change the namespaces in package-info.java without changing the source WSDL?

Is there a way to easily (i.e. not with a separate @Bean method for each) create a separate marshaller for each package that could all then be added to the DefaultMethodEndpointAdapter?

Is there another way to implement all these Outbound Message receivers?


回答1:


Is there a way to change the namespaces?

If you did they wouldn't match the namespaces in the actuall message, so it wouldn't be unmarshallable.

Is there a way to easily create a separate marshaller for each package?

Well, here's a way to do it.

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

Couple of caveats on this:

  • If deploying via a jar, then classpath directories don't exist, so will need an alternate way to get the package names.
  • registerSingleton appears to break some application contexts - causing unrelated beans to be no longer be found. I have no idea why this is.


来源:https://stackoverflow.com/questions/39346061/how-to-implement-multiple-sfdc-outbound-message-receivers-in-the-same-spring-ser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!