1

I'm using the Metro stack bundled with Java 6 SE to call a web service. The web service expects XML as a parameter. I use JAXB classes to create content and pass my JAXB root element to the web service endpoint.

Now to my Problem: I can't find any way to make the marshaller include the schemaLocation of the XSD file since I can't directly access the marshaller. (If you have direct access to the marshaller it is possible do set the schemalocation as a property, but when using metro, all the marshalling seems to be happening internally.)

I've tried setting the xsi:schemaLocation in the XmlSchema annotation in the generated package-info.java class, but this had no effect on the xml generated.

Another point is that when creating a web service client and calling a web service in an Java SE environment, certain annotations like @UsesJAXBContext, @WebServiceClient and @XmlSchema seem to be ignored. (I must state here that I am a beginner in terms of Java web services)

Arquebus
  • 87
  • 2
  • 7

1 Answers1

2

Ok, here's what I now know. This has been a problem for me for months.

First, you have to change the JAXBContext used by JAX-WS. To do this use the @UsesJAXBContext annotation on the server. (com.sun.xml.ws.developer.UsesJAXBContext)

Then, in your factory implementation, you have to return custom Bridges in this method.

public Bridge createBridge(final TypeReference typereference)

Then your custom bridge needs to set the marshaller property to set the namespace mapper you want to use.

Here's my example.

@WebService(serviceName = ...)
@UsesJAXBContext(MyContextFactory.class)
public class SoapServer { ... }

and the factory class ...

public static class MyContextFactory implements JAXBContextFactory
{
    @Override
    public JAXBRIContext createJAXBContext(final SEIModel sei,
            @SuppressWarnings("rawtypes") final List<Class> classesToBind, final List<TypeReference> typeReferences)
            throws JAXBException
    {
        JAXBRIContext context = JAXBContextFactory.DEFAULT.createJAXBContext(sei, classesToBind, typeReferences);
        return new MyJaxwsContext(context);
    }
}

and the JAXB Context impelementation...

public class MyContext extends JAXBRIContext
{
/** the actual context */
private final JAXBRIContext delegate;

public MyContext(final JAXBRIContext createContext)
{
    this.delegate = createContext;
}

public Bridge createBridge(final TypeReference arg0)
{
    return new MyBridge((JAXBContextImpl) delegate, delegate.createBridge(arg0));
}

and now the Bridge implementation...

public class MyBridge extends Bridge
{
private final Bridge delegate;

protected MyBridge(final JAXBContextImpl context, final Bridge delegate)
{
    super(context);
    this.delegate = delegate;
}

// an example marshal call. There are many more...
public void marshal(final Marshaller m, final Object object, final ContentHandler contentHandler)
        throws JAXBException
{
    m.setProperty("com.sun.xml.bind.namespacePrefixMapper", namespaceMapper);
    delegate.marshal(m, object, contentHandler);
}

NOTE: I have just wrapped the existing implementation. All I wanted was to be able to fix the namespace names. From my reading of the source (JAXWS), this is the only way to get to the marshaller.

NOTE2 There is a downcast to an RI final class. This only works with the reference implementation. YMMV

Zagrev
  • 2,000
  • 11
  • 8
  • Thank you for your reply. However your suggestion seems to be aimed at developers who have access to the server side i.e. the web service implementation. This is not the case. I am only creating a web service client. The only information I have about the web service is the wsdl and a documentation that recommends putting the schemalocation of the xsd file in the xml that is passed to the webservice end point – Arquebus Oct 12 '12 at 06:40
  • So what's the real problem? You cannot call the webservice because you get what error? Or is it more fundamental? – Zagrev Oct 12 '12 at 21:39
  • It's a fundamental "problem".I can call the webservice and I am neither getting any warnings or errors. Its just that the webservice provider recommends setting the schemalocation of the business xsd, that describes the business data schema, into the xml that is to be uploaded.I'm wondering why there is no way to do this in a Java SE environment when using the JAXB Metro stack - i.e. having no access to the marshaller. – Arquebus Oct 17 '12 at 08:01
  • The web service has all the schema is needs to communicate, specified in the WSDL, so I don't understand what you need to set. Since you receive no errors or warnings, then the call to the web service is working, right? – Zagrev Oct 17 '12 at 13:39
  • After rethinking the whole issue, I guess you're right. The WSDL has a link to the XSD so there is no need to set the schemaLocation additionally in the XML. Thanks! – Arquebus Oct 19 '12 at 09:31