How to declare a element for complex data type defined in a xsd file located in jar file - spring-boot

I have a below xsd file in a jar dependency file in a Spring boot project. The xsd does not declare the element declaration, which is required by spring boot validation. So I am trying to add another xsd in my project resource folder to declare element type.
XSD in Jar file: /wsdl/xsd/UserService-v1-0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema targetNamespace="http://usermanagement.com/userservice/xsd/2014/07"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:userservice="http://usermanagement.com/userservice/xsd/2014/07"
elementFormDefault="qualified">
<xsd:import namespace="http://usermanagement.com/userservice/common/xsd/2014/09" schemaLocation="userserviceCommon-v1-0.xsd"/>
<xsd:import namespace="http://usermanagement.com/userserviceabsolute/common/xsd/2014/09" schemaLocation="userserviceAbsoluteCommon-v1-0.xsd"/>
<xsd:complexType name="GetUsersRequest">
<xsd:attribute name="language" type="xsd:language" use="optional" default="en" />
</xsd:complexType>
</xsd:schema>
Please note that I tried to keep the complex type simple by removing some of the elements for this post. The location of file is /wsdl/xsd.
XSD to declare the element in the main Project resource: /wsdl/xsd/UserService-type-v1-0.xsd
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema targetNamespace="http://usermanagement.com/userservice/wsdl/userserviceService-v1-0"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:userservice="http://usermanagement.com/userservice/xsd/2014/07"
elementFormDefault="qualified">
<import namespace="http://usermanagement.com/userservice/xsd/2014/07" schemaLocation="jar:file://{path to the jar}/!/wsdl/xsd/userserviceService-v1-0.xsd"/>
<element name="GetUsersRequest" type="userservice:GetUsersRequest"/>
</xsd:schema>
As per my understanding we need to refer to the schemaLocation of xsd file in jar using notation "jar:file://{path to the jar}/!/wsdl/xsd/userserviceService-v1-0.xsd".
However I am not sure how to declare the path to the jar. Also not sure if this is the only way to refer to the definitions in the xsd in the jar files. In the above approach when ever a new version of jar is released we need to update the xsd file.
Also including the Spring WS schema validation config:
#Configuration
public class MyWsValidatorConfig extends WsConfigurerAdapter {
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
PayloadValidatingInterceptor validatingInterceptor = new PayloadValidatingInterceptor();
validatingInterceptor.setValidateRequest(true);
validatingInterceptor.setValidateResponse(true);
validatingInterceptor.setXsdSchemaCollection(new XsdSchemaCollection() {
#Override
public XsdSchema[] getXsdSchemas() {
return null;
}
#Override
public XmlValidator createValidator() {
try {
return XmlValidatorFactory.createValidator(getSchemas(), "http://www.w3.org/2001/XMLSchema");
} catch (Exception e) {
log.error("Failed to create validator e={}", e);
}
return null;
}
public Resource[] getSchemas() {
List<Resource> schemaResources = new ArrayList<>();
schemaResources.add(new ClassPathResource("/wsdl/xsd/UserService-v1-0.xsd"));
schemaResources.add(new ClassPathResource("/wsdl/xsd/UserService-type-v1-0.xsd"));
return schemaResources.toArray(new Resource[schemaResources.size()]);
}
});
interceptors.add(validatingInterceptor);
}
}
This is the first time I am working with XSD and SOAP web services. Able to cross other hurdles but got stuck with this issue.
Please help.

Related

WELD-001408: Unsatisfied dependencies for type Gson with qualifiers #Default

All my other Injections are working but it's not working with gson. I have the feeling it's because it's an external package, but I can't resolve the issue. Here are my relevant files:
Producer:
public class GsonFactory {
#Produces
public Gson createGson(){return new GsonBuilder().createGson();}
}
injectionpoint:
#ApplicationScoped
public class SoundcloudAPIWrapper implements Serializable{
#Inject
private Gson gson;
public SoundcloudAPIWrapper() {}
...
}
Beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
bean-discovery-mode="all" version="2.0">
</beans>
like #maress pointed out in the comment, I needed to replace #javax.ws.rs.Produces with #javax.enterprise.inject.Produces. It's now working

Access a static file saved inside the WEB-INF folder of a Servlet from the doPost() method

I'm trying to access some images that I have saved in my Servlet inside the src/main/webapp/WEB-INF/imgs folder, this way:
link
I tryed to access these images with this code within the doPost method of my Servlet:
InputStream s = this.getClass().getClassLoader().getResourceAsStream("http://cardimgs.org/imgs/cardbackground1.jpg");
Movie movie = new Movie();
try {
byte[] bytes = IOUtils.toByteArray(s);
movie.setImage(bytes);
} catch (IOException e) {
e.printStackTrace();
}
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
// Store the image in App Engine's datastore
pm.makePersistent(movie);
} finally {
pm.close();
}
Movie class:
link 2,
the reason why I used the specified urlto create the InputStream is because in my appengine-web.xml I have:
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>myApplicationId</application>
<version>1</version>
<threadsafe>true</threadsafe>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
</system-properties>
<static-files>
<include path="/**.jpg"/>
<include path="/imgs" >
<http-header name="Access-Control-Allow-Origin" value="http://cardimgs.org" />
</include>
</static-files>
</appengine-web-app>
where I try to define my static files.
My problem is, though, that with the above code I can't access my file and fill the InputStream, which appears to be null, therefore returning a NullPointerException.
How can I successfully access my static files?
ClassLoader.getResourceAsStream() loads resources using *the class loader**. It thus looks for them in the classpath. The classpath of a web-app is constitued from WEB-INF/classes and from all the jars inside WEB-INF/lib. The path it expects looks like com/mycompany/myproject/somefile.txt. It can't be a HTTP URL.
What you need is ServletContext.getResourceAsStream("/WEB-INF/imgs/cardbackground1.jpg"). This method loads a resource from anywhere inside the web-app.

Change Implementation for Spring Namespaces (exchange a bean)

I have a question about Spring Integration (or basically Spring in common):
I use the a WebService Inbound Gateway in my Spring XML configuration:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:int-ws="http://www.springframework.org/schema/integration/ws"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd" >
<int-ws:inbound-gateway
id="ws-in-gw-user"
request-channel="in-user"
reply-channel="out-user"
mapped-request-headers="*"
/>
...
</beans>
When I use <int-ws:inbound-gateway> Tag, a SimpleWebServiceInboundGateway is created. Now I want to exchange this implemantation with a self written extension of this class. Any ideas how to do it?
you could use a BeanPostProcessor bean.
import org.springframework.beans.factory.config.BeanPostProcessor;
public class SimpleWebServiceInboundGatewayBeanPostProcessor implements BeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String beanName){
if(bean instanceof SimpleWebServiceInboundGateway) {
return new MyCustomWebSerivceInboundGateway();
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
In your config:
<bean class="....SimpleWebServiceInboundGatewayBeanPostProcessor" />
A BeanPostProcessor allows you to exhange beans during initialization.

Returning JAXB-generated elements from Spring Boot Controller

I'm generating a plethora of Java files from http://www.ncpdp.org's XSD files (only available to members). After generating them, I'd like to use them in my Spring Controllers, but I'm having problems getting responses converted to XML.
I've tried returning the element itself, as well as JAXBElement<T>, but neither seems to work. The test below fails:
java.lang.AssertionError: Status
Expected :200
Actual :406
#Test
public void testHelloWorld() throws Exception {
mockMvc.perform(get("/api/message")
.accept(MediaType.APPLICATION_XML)
.contentType(MediaType.APPLICATION_XML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_XML));
}
Here's my Controller:
import org.ncpdp.schema.transport.MessageType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HelloWorldController {
#RequestMapping(value = "/api/message", method = RequestMethod.GET)
public MessageType messageType() {
return new MessageType();
}
}
I've tried creating a MvcConfig to override Spring Boot's MVC config, but it doesn't seem to be working.
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(marshallingHttpMessageConverter());
}
#Bean
public MarshallingHttpMessageConverter marshallingHttpMessageConverter() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
jaxb2Marshaller.setPackagesToScan(new String[]{"com.ncpdb.schema.transport"});
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter();
converter.setMarshaller(jaxb2Marshaller);
converter.setUnmarshaller(jaxb2Marshaller);
converter.setSupportedMediaTypes(Arrays.asList(MediaType.APPLICATION_XML));
return converter;
}
}
What do I need to do to get Spring MVC to marshall my generated JAXB objects as XML?
I was able to solve this by creating a bindings.xjb file in the same directory as my schemas. This causes JAXB to generate #XmlRootElement on classes.
<?xml version="1.0"?>
<jxb:bindings version="1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd">
<jxb:bindings schemaLocation="transport.xsd" node="/xsd:schema">
<jxb:globalBindings>
<xjc:simple/>
</jxb:globalBindings>
</jxb:bindings>
</jxb:bindings>
To add namespaces prefixes to the returned XML, I had to modify the maven-jaxb2-plugin to add a couple arguments.
<arg>-extension</arg>
<arg>-Xnamespace-prefix</arg>
And add a dependency:
<dependencies>
<dependency>
<groupId>org.jvnet.jaxb2_commons</groupId>
<artifactId>jaxb2-namespace-prefix</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
Then modify my bindings.xjb to include this:
<?xml version="1.0"?>
<jxb:bindings version="1.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:namespace="http://jaxb2-commons.dev.java.net/namespace-prefix"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd
http://jaxb2-commons.dev.java.net/namespace-prefix http://java.net/projects/jaxb2-commons/sources/svn/content/namespace-prefix/trunk/src/main/resources/prefix-namespace-schema.xsd">
<jxb:bindings schemaLocation="transport.xsd" node="/xsd:schema">
<jxb:globalBindings>
<xjc:simple/>
</jxb:globalBindings>
<jxb:schemaBindings>
<jxb:package name="org.ncpdp.schema.transport"/>
</jxb:schemaBindings>
<jxb:bindings>
<namespace:prefix name="transport"/>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
I learned how to do this from https://java.net/projects/jaxb2-commons/pages/Namespace-prefix. I also found http://blog.frankel.ch/customize-your-jaxb-bindings to be a good resource on how to customize JAXB bindings.

Consume webservice service in SPRING-WS using wsdl

I have WSDL with me .eg: /sample/hello?wsdl . I want to invoke the service the webservice by configuring in Spring-ws. I passed this wsdl as parameter to tags in springconfig.xml.
Can anyone please tell me how to consume this webservice in Spring-ws.
1. Set up project dependencies
add the following dependencies to the pom file:
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.2.5</version>
</dependency>
2. Set up web service application context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.yourcomany.model" />
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory" />
<property name="marshaller" ref="marshaller"></property>
<property name="unmarshaller" ref="marshaller"></property>
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.HttpComponentsMessageSender" />
</property>
<property name="defaultUri"
value="http://<hostname>:<portnumber>/sample/hello" />
</bean>
</beans>
3. Set up model classes which would map to your SOAP request/response objects
For example, if your SOAP request XML looked like
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xxx="http://yourcomapny.com">
<soapenv:Header/>
<soapenv:Body>
<xxx:InputParameters>
<xxx:paramONE>1</xxx:paramONE>
</xxx:InputParameters>
</soapenv:Body>
</soapenv:Envelope>
and your SOAP response XML looked like:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header>
...
</env:Header>
<env:Body>
<xxx:OutputParameters xmlns:xxx="http://yourcompany.com">
<xxx:paramONE>0</xxx:paramONE>
</xxx:OutputParameters>
</env:Body>
</env:Envelope>
the corresponding classes (under the package you specified in the marshaller bean: com.yourcompany.model) would be respectively:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "paramONE" })
#XmlRootElement(name = "InputParameters", namespace = "http://yourcompany.com")
public class InputParameters {
#XmlElement(required = true, namespace = "http://yourcompany.com")
private String paramONE;
public String getParamONE() {
return paramONE;
}
public void setParamONE(String paramONE) {
this.paramONE = paramONE;
}
}
and
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = { "paramONE" })
#XmlRootElement(name = "OutputParameters", namespace = "http://yourcompany.com")
public class OutputParameters {
#XmlElement(required = true, namespace = "http://yourcompany.com")
private BigDecimal paramONE;
public BigDecimal getParamONE() {
return this.paramONE;
}
public void setParamONE(BigDecimal paramONE) {
this.paramONE= paramONE;
}
}
4. Add an Object Factory (under package com.yourcompany.model) to create request/response objects
#XmlRegistry
public class ObjectFactory {
public ObjectFactory() {
}
public InputParameters createYourRequest() {
return new InputParameters();
}
public OutputParameters createYourResponse() {
return new OutputParameters();
}
}
5. Create a client to consume the service
Interface:
public interface YourService {
BigDecimal getValue(String paramOne);
}
Implementation
#Component("yourServiceClient")
public class YourServiceClient implements YourService {
private static final ObjectFactory WS_CLIENT_FACTORY = new ObjectFactory();
private WebServiceTemplate webServiceTemplate;
#Autowired
public YourServiceClient(WebServiceTemplate webServiceTemplate) {
this.webServiceTemplate = webServiceTemplate;
}
#Override
public BigDecimal getValue(String paramOne) {
InputParameters request = WS_CLIENT_FACTORY
.createYourRequest();
request.setParamONE(paramOne);
OutputParameters response = (OutputParameters) webServiceTemplate
.marshalSendAndReceive(request);
return response.getParamONE();
}
}
#Taoufik Mohdit answer is complete!!
To build the input and output objects you can use Webservice-Client: Common approach with Spring WS, JAXB and just one WSDL file? to some how build these objects automatically
Given that this question is still active I thought I would post an update that reflects a number of changes that the recent version of the Spring Web Services framework and Spring in general introduce:
The introduction of Spring Boot allows to leverage 'starter' POMs to simplify your Maven configuration. There is a specific spring-boot-starter-web-services starter for Spring-WS
Instead of specifying Spring configuration files using XML, Spring JavaConfig was introduced which provides a type-safe, pure-Java option for configuring Spring.
Generation of request/response objects based on a given WSDL file can be automated using Maven plugins. The plugin used by the Spring-WS examples is the maven-jaxb2-plugin.
The WebServiceTemplate is still the core class for client-side Web service access. For more information you can check this detailed example on how to consume a web service using Spring-WS starting from a WSDL file that I wrote.

Resources