In base a official Spring WS documentation, il suffisso Richiesta/Risposta è quello predefinito utilizzato per determinare automaticamente la richiesta/risposta e come tale generare il WSDL previsto.
DefaultWsdl11Definition che crea un WSDL da uno schema XSD. Questa definizione esegue iterazioni su tutti gli elementi elemento presenti nello schema e crea un messaggio per tutti gli elementi. Successivamente, crea un'operazione WSDL per tutti i messaggi che terminano con la richiesta definita o il suffisso della risposta. Il suffisso di richiesta predefinito è Request; il suffisso di risposta predefinito è Response, sebbene possano essere modificati impostando rispettivamente le proprietà requestSuffix e responseSuffix.
È possibile quindi, nel codice di esempio citato, cambiare il suffisso nella classe di configurazione WebServiceConfig
, defaultWsdl11Definition
metodo, aggiungendo il metodo seguente invocazione:
wsdl11Definition.setRequestSuffix("your-new-prefix-here");
È possibile, ad esempio, impostarlo Req
invece di Request
, la generazione genererà automaticamente una nuova classe GetCountryReq
, il codice di ApplicationTests
e CountryEndpoint
dovrà quindi essere adattato manualmente, rimuovendo gli errori di compilazione (come farebbero ancora riferimento alloesistente in precedenzaclasse), ma assicurandosi anche di modificare l'attributo localPart = "getCountryReq"
dell'annotazione @PayloadRoot
nella classe CountryEndPoint
.
Ho provato e build andato bene e WSDL è stato aggiornato di conseguenza.
Si tratta di modificare il suffisso predefinito con un altro suffisso. Ma che ne dici di cambiarlo in un suffisso vuoto?
wsdl11Definition.setRequestSuffix("");
eccezione: suffisso non deve essere vuota. La primavera non lo supporta Secondo questo thread:
In sostanza, il problema è questo:
Dobbiamo distinguere quali elementi dello schema sono i messaggi WSDL, e quali no.
Di tutti i messaggi wsdl, dobbiamo capire quali sono i messaggi di input (richiesta).
Di tutti i messaggi wsdl, dobbiamo capire quali sono i messaggi di uscita (risposta).
The DefaultWsdl11Definition lo identifica con i suffissi. O, in particolare, delega a SuffixBasedMessagesProvider e SuffixBasedPortTypesProvider di farlo.
Quindi, se si dispone di un altro modo preferibile per determinare ciò che rende un messaggio di input/output, è necessario scrivere il proprio messageprovider e/o porttypesprovider.
In poche parole: non esiste un modo generico per Spring-WS per determinare cosa costituisce una richiesta e una risposta, piuttosto che utilizzare i suffissi.
Nota: il manifesto di questo messaggio è stato Arjen Poutsma, autore della classe DefaultWsdl11Definition
(secondo javadoc), il componente che gestisce la mappatura automatica in base a queste convenzioni suffisso.
Ma lui lascia una porta aperta: scrivendo il proprio SuffixBasedMessagesProvider
e SuffixBasedPortTypesProvider
. Tuttavia, ha anche lasciato tutto come privato nel DefaultWsdl11Definition
(dove questi provider sono istanziati), quindi è anche necessario scrivere (copiare) il proprio mappatore di definizione WSDL11.
Qui è il processo che ho seguito poi:
- Crea il tuo CustomSuffixBasedMessagesProvider, l'override del metodo
setRequestSuffix
e rimuovendo il controllo sul suffisso vuoto, nel metodo isMessageElement
si avrebbe bisogno di gestire la nuova mappatura
- Crea il tuo CustomSuffixBasedPortTypesProvider, sovrascrivendo il metodo
setRequestSuffix
e rimuovendo il controllo sul suffisso vuoto, nei metodi getOperationName
e isInputMessage
che ti serviranno per gestire la nuova mappatura
- Creare la propria CustomWsdl11Definition come copia della DefaultWsdl11Definition esistente e creare un'istanza dei propri provider creati sopra
- Modificare la classe
WebServiceConfig
, defaultWsdl11Definition
, per utilizzare la propria CustomWsdl11Definition per applicare l'intera personalizzazione.
Tuttavia, il suffisso vuoto viene fornito con un po 'di difficoltà, dal momento che andrebbe bene per qualsiasi elemento (ovvero, ogni elemento ha un suffisso vuoto). Questo è il motivo per cui ho menzionato la gestione di isMessageElement
, isInputMessage
e getOperationName
: su WSDL in crescita, si può facilmente finire con l'harcoding del mapping (per la richiesta GetCountry, GetCountryResponse è la risposta) o il passaggio di una proprietà/mappa (come suggerito nello thread di cui sopra) , ma ripeti di nuovo la maggior parte del tuo XSD nella tua classe di configurazione WebServiceConfig
, rendendo difficile la manutenzione, la risoluzione dei problemi e la condivisione.
Quindi, vorrei davvero suggerire di non intraprendere questo viaggio e attenersi al suffisso predefinito (se possibile) o crearne uno nuovo, ma evitare il suffisso vuoto (non sono ammessi dalla libreria dopo tutto).
Ma da quando ho preso il viaggio, ecco la soluzione di lavoro:
Il MySuffixBasedMessagesProvider classe personalizzata (importazioni rimossi per brevità):
package hello;
public class MySuffixBasedMessagesProvider extends SuffixBasedMessagesProvider {
protected String requestSuffix = DEFAULT_REQUEST_SUFFIX;
public String getRequestSuffix() {
return this.requestSuffix;
}
public void setRequestSuffix(String requestSuffix) {
this.requestSuffix = requestSuffix;
}
@Override
protected boolean isMessageElement(Element element) {
if (isMessageElement0(element)) {
String elementName = getElementName(element);
Assert.hasText(elementName, "Element has no name");
return elementName.endsWith(getResponseSuffix())
|| (getRequestSuffix().isEmpty() ? true : elementName.endsWith(getRequestSuffix()))
|| elementName.endsWith(getFaultSuffix());
}
return false;
}
protected boolean isMessageElement0(Element element) {
return "element".equals(element.getLocalName())
&& "http://www.w3.org/2001/XMLSchema".equals(element.getNamespaceURI());
}
}
Il MySuffixBasedPortTypesProvider classe personalizzata (importazioni rimosso per brevità):
package hello;
public class MySuffixBasedPortTypesProvider extends SuffixBasedPortTypesProvider {
private String requestSuffix = DEFAULT_REQUEST_SUFFIX;
public String getRequestSuffix() {
return requestSuffix;
}
public void setRequestSuffix(String requestSuffix) {
this.requestSuffix = requestSuffix;
}
@Override
protected String getOperationName(Message message) {
String messageName = getMessageName(message);
String result = null;
if (messageName != null) {
if (messageName.endsWith(getResponseSuffix())) {
result = messageName.substring(0, messageName.length() - getResponseSuffix().length());
} else if (messageName.endsWith(getFaultSuffix())) {
result = messageName.substring(0, messageName.length() - getFaultSuffix().length());
} else if (messageName.endsWith(getRequestSuffix())) {
result = messageName.substring(0, messageName.length() - getRequestSuffix().length());
}
}
return result;
}
@Override
protected boolean isInputMessage(Message message) {
String messageName = getMessageName(message);
return messageName != null && !messageName.endsWith(getResponseSuffix());
}
private String getMessageName(Message message) {
return message.getQName().getLocalPart();
}
}
Il MyWsdl11Definition classe personalizzata (essenzialmente una copia di default, basta istanziare classi sopra, importazioni rimossa per brevità):
package hello;
public class MyWsdl11Definition implements Wsdl11Definition, InitializingBean {
private final InliningXsdSchemaTypesProvider typesProvider = new InliningXsdSchemaTypesProvider();
private final SuffixBasedMessagesProvider messagesProvider = new MySuffixBasedMessagesProvider();
private final SuffixBasedPortTypesProvider portTypesProvider = new MySuffixBasedPortTypesProvider();
private final SoapProvider soapProvider = new SoapProvider();
private final ProviderBasedWsdl4jDefinition delegate = new ProviderBasedWsdl4jDefinition();
private String serviceName;
public MyWsdl11Definition() {
delegate.setTypesProvider(typesProvider);
delegate.setMessagesProvider(messagesProvider);
delegate.setPortTypesProvider(portTypesProvider);
delegate.setBindingsProvider(soapProvider);
delegate.setServicesProvider(soapProvider);
}
public void setTargetNamespace(String targetNamespace) {
delegate.setTargetNamespace(targetNamespace);
}
public void setSchema(XsdSchema schema) {
typesProvider.setSchema(schema);
}
public void setSchemaCollection(XsdSchemaCollection schemaCollection) {
typesProvider.setSchemaCollection(schemaCollection);
}
public void setPortTypeName(String portTypeName) {
portTypesProvider.setPortTypeName(portTypeName);
}
public void setRequestSuffix(String requestSuffix) {
portTypesProvider.setRequestSuffix(requestSuffix);
messagesProvider.setRequestSuffix(requestSuffix);
}
public void setResponseSuffix(String responseSuffix) {
portTypesProvider.setResponseSuffix(responseSuffix);
messagesProvider.setResponseSuffix(responseSuffix);
}
public void setFaultSuffix(String faultSuffix) {
portTypesProvider.setFaultSuffix(faultSuffix);
messagesProvider.setFaultSuffix(faultSuffix);
}
public void setCreateSoap11Binding(boolean createSoap11Binding) {
soapProvider.setCreateSoap11Binding(createSoap11Binding);
}
public void setCreateSoap12Binding(boolean createSoap12Binding) {
soapProvider.setCreateSoap12Binding(createSoap12Binding);
}
public void setSoapActions(Properties soapActions) {
soapProvider.setSoapActions(soapActions);
}
public void setTransportUri(String transportUri) {
soapProvider.setTransportUri(transportUri);
}
public void setLocationUri(String locationUri) {
soapProvider.setLocationUri(locationUri);
}
public void setServiceName(String serviceName) {
soapProvider.setServiceName(serviceName);
this.serviceName = serviceName;
}
@Override
public void afterPropertiesSet() throws Exception {
if (!StringUtils.hasText(delegate.getTargetNamespace()) && typesProvider.getSchemaCollection() != null &&
typesProvider.getSchemaCollection().getXsdSchemas().length > 0) {
XsdSchema schema = typesProvider.getSchemaCollection().getXsdSchemas()[0];
setTargetNamespace(schema.getTargetNamespace());
}
if (!StringUtils.hasText(serviceName) && StringUtils.hasText(portTypesProvider.getPortTypeName())) {
soapProvider.setServiceName(portTypesProvider.getPortTypeName() + "Service");
}
delegate.afterPropertiesSet();
}
@Override
public Source getSource() {
return delegate.getSource();
}
}
Inoltre, il metodo della classe WebServiceConfig
defaultWsdl11Definition
cambierebbero come segue (a utilizzare la personalizzazione sopra):
@Bean(name = "countries")
public Wsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
MyWsdl11Definition wsdl11Definition = new MyWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setRequestSuffix("");
wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
Nota la wsdl11Definition.setRequestSuffix("");
che definisce efficacemente il suffisso a vuoto.
Dopo questa personalizzazione, è possibile modificare XSD rimuovendo il suffisso Request, verrà generata la nuova classe GetCountry, sarà necessario rimuovere manualmente il GetCountryRequest esistente e correggere gli errori di compilazione come menzionato sopra (test ed endpoint class , non dimenticare di aggiornare anche l'annotazione @PayloadRoot).
Build funzionerebbe correttamente. L'esecuzione del Application
principale, il WSDL generato sarebbe quindi contenere come richiesto:
<wsdl:binding name="CountriesPortSoap11" type="tns:CountriesPort">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getCountry">
<soap:operation soapAction=""/>
<wsdl:input name="getCountry">
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getCountryResponse">
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
Speranza che aiuta. Questo è un esempio reale di ciò che offre la convenzione sulla configurazione e cosa invece un piccolo cambiamento imprevisto in un framework significherebbe in termini di scrittura del codice e aggiunta di personalizzazione.
Per tutti voi che stanno avendo problemi simili: utilizzare org.apache.cxf e generare l'endpoint da WSDL con wsdl2java. È più semplice e la lib in realtà consente sia soap 1.1 che 1.2 sullo stesso endpoint. – Dariusz