Archive

Posts Tagged ‘web service’

[wsdlc] [ERROR] A class/interface with the same name “com.mydomain.layer.inbound.ws.ValidateResponse” is already in use. Use a class customizat ion to resolve this conflict.

6 February 2016 Leave a comment

I got the error [wsdlc] [ERROR] A class/interface with the same name "com.mydomain.layer.inbound.ws.ValidateResponse" is already in use. Use a class customization to resolve this conflict. a few days ago when I tried to generate the Java code from a WSDL file, using Oracle’s wsdlc Ant task. The problem is caused by having two elements with the same name, but with a different namespace, in the WSDL file. For example the following bit of code will result in the error above:

<s:element name="ValidateResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="ValidateResult" type="tns:ValidateResponse" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:complexType name="ValidateResponse">
        <s:complexContent mixed="false">
          <s:extension base="tns:Response">
            <s:sequence>
              <s:element minOccurs="1" maxOccurs="1" name="Status" type="tns:ResponseStatus" />
              <s:element minOccurs="0" maxOccurs="1" name="SubscriptionExpiry" type="s:string" />
              <s:element minOccurs="0" maxOccurs="1" name="Allowed" type="tns:ArrayOfGuid" />
            </s:sequence>
          </s:extension>
        </s:complexContent>
      </s:complexType>

The solution to this is to use a JAXB Customisation Binding, as explained here. By using a JAXB Customisation Binding you can essentially bind a WSDL element to another type and therefore resolve the conflict, since in the generated Java code you end up with two different artifacts.

There are two ways do it. The first one is to use an external JAXB Customisation Binding file. Unfortunately this solution did not work for me. Not sure what the problem was. The second solution is to use inline JAXB Customisation Binding code. Fortunately this solution did work for me. By inlining the JAXB binding you end up with the following bit of code

      <s:element name="ValidateResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="ValidateResult" type="tns:ValidateResponse" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:complexType name="ValidateResponse">
        <s:annotation>
          <s:appinfo>
            <jaxb:class name="ValidateResponseComplexType"/>
          </s:appinfo>
        </s:annotation>
      <s:complexContent mixed="false">
        <s:extension base="tns:Response">
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="Status" type="tns:ResponseStatus" />
            <s:element minOccurs="0" maxOccurs="1" name="SubscriptionExpiry" type="s:string" />
            <s:element minOccurs="0" maxOccurs="1" name="Allowed" type="tns:ArrayOfGuid" />
          </s:sequence>
        </s:extension>
      </s:complexContent>
      </s:complexType>

When the wsdlc runs you will end up with the different classes for the ValidateResponse element: ValidateResponse and ValidateResponseComplexType. Of course you will also need to define the jaxb namespace: xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" in the WSDL file.

Advertisements
Categories: Java, Web Services Tags: ,

How to resolve circular dependency problems with a Document Literal Wrapped web service

15 June 2010 1 comment

A circular dependencies problem came up while I was trying to implement a Document Literal Wrapped style web service in JBoss. Having gone through several forums the main solution suggested was to use an RPC style web service since you cannot represent circular dependencies with a Document Literal. Alas, the jboss web services implementation does not support RPC ENCODED style web services since it considers it deprecated. An alternative solution was to use Axis but since the project was already using the JBoss implementation I didn’t want to add another one.

Before we delve into the solution lets see what a circular dependency is. In a few words, a circular dependency occurs when we have two objects, and each one refers to each other. For instance a payment and a receipt in the real world. You pay for something and you get a receipt. And the receipt you got refers to the payment you made. If we are to model this in Java we would have two classes, Payment and Receipt which could look like the following

class Payment
{
	private int paymentId;
	private Receipt receipt;
	
	public Payment() {
	}
	
	public void setPaymentId(int paymentId) {
		this.paymentId = paymentId;
	}

	public int getPaymentId() {
		return paymentId;
	}
	
	public void setReceipt(Receipt receipt) {
		this.receipt = receipt;
	}
	public Receipt getReceipt() {
		return receipt;
	}
}

class Receipt
{
	private int receiptId;
	private Payment payment;

	public Receipt() {
	}

	public void setReceiptId(int receiptId) {
		this.receiptId = receiptId;
	}

	public int getReceiptId() {
		return receiptId;
	}
	
	public void setPayment(Payment payment) {
		this.payment = payment;
	}

	public Payment getPayment() {
		return payment;
	}
}

This is circular dependency, Payment refers to Receipt and Receipt refers to Payment. Java can represent this easily in the object graph but in XML this is a bit tricky if you create the WSDL automatically.

Lets assume we have a web service that uses one of our classes.

@WebService(name="PaymentWS")
@SOAPBinding(style=SOAPBinding.Style.DOCUMENT, use=SOAPBinding.Use.LITERAL, parameterStyle=SOAPBinding.ParameterStyle.WRAPPED) 
public class PaymentWS
{
	@WebMethod
	public void buy(Payment payment)
	{
	}
}

If we take the WSDL of our web service and generate the relevant classes and then we write a java client to connect to our web service we can write something like the following

public class Client {

    public static void main(String [] arguments)
    {
        PaymentWSService service = new PaymentWSService();
        PaymentWS ser = service.getPaymentWSPort();

        Payment payment = new Payment();
        payment.setPaymentId(10);

        Receipt receipt = new Receipt();
        receipt.setReceiptId(20);
        receipt.setPayment(payment);
        
        payment.setReceipt(receipt);
        
        ser.buy(payment);
    }
}

When we run this it throws a MarshalException

Caused by: javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML:

This is because of the circular dependency of Payment and Receipt because the XML of the SOAP message tries to nest a chunk of XML Payment within the XML Receipt element, and a chunck or XML Receipt within the XML Payment and so on. We can get around this problem by using the @XmlIDREF and @XmlID annotations on the generated Java classes to instruct the runtime that instead of nesting the XML elements within each other simply to use a reference to them. Our generated java classes look like the following

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "payment", propOrder = {
    "paymentId",
    "receipt"
})
public class Payment {

    protected int paymentId;
    protected Receipt receipt;
    ...
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "receipt", propOrder = {
    "payment",
    "receiptId"
})
public class Receipt {

    protected Payment payment;
    protected int receiptId;
    ...
}

and after adding the annotations they become

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "payment", propOrder = {
    "paymentId",
    "receipt"
})
public class Payment {

    protected int paymentId;
    @XmlIDREF
    protected Receipt receipt;
    ...
}

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "receipt", propOrder = {
    "payment",
    "receiptId"
})
public class Receipt {

    protected Payment payment;
    @XmlID
    protected int receiptId;
    ...
}

Unfortunatelly this still does not work and it throws a WebServiceException which is caused by

Caused by: java.security.PrivilegedActionException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
Property "receiptId" has an XmlID annotation but its type is not String.

This is because the runtime expects the type of the XmlId to be a string. Not sure why this is mandatory (I guess the designers where afraid that people might not implement the toString() method correctly). The workaround is to add an @XmlJavaTypeAdapter annotation which will adapt our non-String type to a String.

public class IntegerAdapter extends XmlAdapter<String, Integer> {
    
    public Integer unmarshal(String s) {
        return Integer.parseInt(s);
    }

    public String marshal(Integer number) {
        if (number == null) return "";
        
        return number.toString();
    }
}

Since the adapter works only with objects we will also need to modify the Receipt generated class to use an Integer intead of an int.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "receipt", propOrder = {
    "payment",
    "receiptId"
})
public class Receipt {

    protected Payment payment;
    @XmlID
    @XmlJavaTypeAdapter(IntegerAdapter.class)
    protected Integer receiptId;
    ...
}

That’s it. A bit tricky but at least it works.