如何在同一个 Spring 服务中实现多个 SFDC 出站消息接收器?
How to implement multiple SFDC Outbound Message receivers in the same Spring service?
对于每条出站消息,Salesforce 提供完整的独立 WSDL。
为单个服务实施Spring服务很容易,使用jaxws-maven-plugin
生成类和@Endpoint
、@PayloadRoot
等进行绑定端点。
但是,对于不同的结构和类型层次结构,多个出站消息都共享相同的 QN(例如 http://soap.sforce.com/2005/09/outbound:notifications
或 urn: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
?
还有其他方法可以实现所有这些出站消息接收器吗?
Is there a way to change the namespaces?
如果您这样做了,它们将不会匹配实际消息中的名称空间,因此它不会是不可解组的。
Is there a way to easily create a separate marshaller for each package?
嗯,这是一种方法。
@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。我不知道这是为什么。
对于每条出站消息,Salesforce 提供完整的独立 WSDL。
为单个服务实施Spring服务很容易,使用jaxws-maven-plugin
生成类和@Endpoint
、@PayloadRoot
等进行绑定端点。
但是,对于不同的结构和类型层次结构,多个出站消息都共享相同的 QN(例如 http://soap.sforce.com/2005/09/outbound:notifications
或 urn: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
?
还有其他方法可以实现所有这些出站消息接收器吗?
Is there a way to change the namespaces?
如果您这样做了,它们将不会匹配实际消息中的名称空间,因此它不会是不可解组的。
Is there a way to easily create a separate marshaller for each package?
嗯,这是一种方法。
@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。我不知道这是为什么。