3

I have one to many mapping in my Pojo classes. A shop has a branch and a branch has many shops Here's Shop's Code:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name="Shop")
public class Shop {

@XmlID
private String name;
@XmlIDREF
@XmlElement(name="ShopBranch",type=Branch.class)
private Branch branch;
//Getter Setter
}

Below is Branch Code:

 @XmlAccessorType(XmlAccessType.FIELD)
public class Branch {
@XmlID
private String name;
private String address;
@XmlIDREF
@XmlElement(nillable=false,required=true)
private List<Shop> shops;
//Getter and Setters
}

I'm publishing a webservice with some basic methods. and my wsimport is generating Branch class as below

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "branch", propOrder = {
    "branchName",
    "address",
    "branchShop"
})
public class Branch {

    @XmlElement(name = "BranchName")
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlID
    @XmlSchemaType(name = "ID")
    protected String branchName;
    protected String address;
    @XmlElementRef(name = "BranchShop", type = JAXBElement.class)
    protected List<JAXBElement<Object>> branchShop;
    //Getter-Setter
    }

I have no idea why it is List<JAXBElement<Object>> and not List<JAXBElement<Shop>>. But anyway. I have a method which returns all branches and that is working fine. When i extract branchShop from branch's instance i'm getting correct size for branchShop list but for all of the items in list getValue is returning NULL. Below is brief code:

PencilCatalog service= new PencilCatalog();
com.pencilhouse.webservices.PencilService port=service.getPencilCatalogPort();
((BindingProvider)port).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, Constant.PENCIL_SERVICE);
    List<Branch> branches= port.getAllBranches();
for(Branch b:branches)
{
    System.out.println("******************Branch:"+b.getBranchName()+" "+b.getAddress()+"******************");
    JAXBElement<Object>o=b.getBranchShop().get(0);
    System.out.println(o+"Value"+o.getScope()+" "+o.getValue());
}

o/p

******************Branch:KukatPalli Steer 2 Kukatpalli****************** javax.xml.bind.JAXBElement@45d9d7beValueclass com.pencilhouse.webservices.Branch null

The WSDL generated is quite large. I'm posting only type of Branch and Shop. I'm publishing webservice using Endpoint

XML generated:

<xs:complexType name="shop">
<xs:sequence>
<xs:element name="name" type="xs:ID" minOccurs="0"/>
<xs:element name="ShopBranch" type="xs:IDREF" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="branch">
<xs:sequence>
<xs:element name="BranchName" type="xs:ID" minOccurs="0"/>
<xs:element name="address" type="xs:string" minOccurs="0"/>
<xs:element name="BranchShop" type="xs:IDREF" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>

Intercepted Information: Request:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getAllBranches xmlns:ns2="PencilServiceHouse"/>
</S:Body>
</S:Envelope>

Response:

<?xml version="1.0" ?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:getAllBranchesResponse xmlns:ns2="PencilServiceHouse">
        <return>
            <name>
                    KukatPalli
            </name>
            <address>
                    Steer 2 Kukatpalli
            </address>
            <shops>
                    Pencil World    <!-- This is Shop Information which is coming as NULL in java, This is Shop's Name field which is declared as id using @XmlId -->
            </shops>
            <shops>
                    Pencils Den
            </shops>
            <shops>
                    Pencils Bag
            </shops>
        </return>
        <return>
            <name>
                    Salt Lake
            </name>
            <address>
                    Sec V Salt Lake
            </address>
            <shops>
                    Pencil World
            </shops>
            <shops>
                    Pencils Den
            </shops>
        </return>
        <return>
            <name>
                    Noida
            </name>
            <address>
                    Noida Sec 43
            </address>
            <shops>
                    Pencils Bag
            </shops>
        </return>
        </ns2:getAllBranchesResponse>
    </S:Body>
</S:Envelope>
Kumar Gaurav
  • 1,287
  • 3
  • 19
  • 47
  • Add your schema (only the relevant part) and the XML. – lexicore Oct 14 '14 at 09:59
  • I'm not writing any xml file by myself. everything is getting generated automatically using wsgen and wsimport which eventually uses jaxb(i suppose) – Kumar Gaurav Oct 14 '14 at 10:02
  • Sorry, you don't post any code on how the `port` and `branches` are created so it's impossible to guess why it is null. Also posting the relevant XML Schema part would help to clarify why you get `JAXBElement` instead of `Shop`. – lexicore Oct 14 '14 at 10:28
  • I have updated the post. Let me know if more code is required – Kumar Gaurav Oct 14 '14 at 11:01
  • Could you please intercept the XML which is returned by the service? Not knowing this XML it's impossible to say what is going on. I guess the XML does not match your classes but it's hard to say without seeing the XML. – lexicore Oct 20 '14 at 11:13
  • I have added intercepted request and response. Please check now. – Kumar Gaurav Oct 21 '14 at 04:58

2 Answers2

1

@XmlIDREF provides a way to specify intra-document references. It is required that each object be refrerenced through a sepearate nested relationship (such as @XmlElement) to get the data into the XML document.

I have written more about @XmlIDREF on my blog:


UPDATE

I saw your blog, I'm getting data in my xml response but the issue is that when i generate my classes on client side using wsimport it is generating type Object for @XmlIDRef and it doesn't set data for these properties as i explained in my question.

In your example you are going: classes -> schema -> classes. Since Java classes and XML Schema are not a perfect match, and JAXB does not put any JAXB specific metadata in the generated schema some information is lost. You can fix this as follows:

You can use an external bindings file to type the IDREF property.

<jaxb:bindings schemaLocation="schema.xsd" node="/xsd:schema">
    <jaxb:bindings node="xsd:complexType[@name='branch']//xsd:element[@name='BranchShop']">
        <jaxb:property>
            <jaxb:baseType name="org.example.Shop"/>
        </jaxb:property>
    </jaxb:bindings>
</jaxb:bindings>
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • I saw your blog, I'm getting data in my xml response but the issue is that when i generate my classes on client side using wsimport it is generating type Object for @XmlIDRef and it doesn't set data for these properties as i explained in my question. – Kumar Gaurav Oct 24 '14 at 04:53
  • @KumarGaurav - I have updated my answer with some information that should help. – bdoughan Oct 24 '14 at 15:52
0

This is not an answer, but it is to big for a comment and uses some formatting, so I have to post it as an answer.


Somehow your examples just don't add up.

First thing which is suspicious to be is that you have two Branch classes. Which already looks weird. Why do you need the second one? Or are these, like, service and client implementations?

Next, your Branch classes use the BranchName and BranchShop elements whereas your XML uses name and shop elements. This does not fit. Seems like your web service does not give the XML you expect. This would explain why the data is missing, but what puzzles me is - why do you get an element in the branchShop at all. I would actually expect the list to be empty but you seem to have something there.

My suggestion would be to figure out, why XML you get does not match your schema and to implement an isolated unmarshalling unit-test to test unmarshalling of the intercepted XML.

lexicore
  • 42,748
  • 17
  • 132
  • 221
  • I have only one Branch Class (On my Webserver end). Another was generated using wsimport on client side. Why there's difference in variable name and thier counter part xml? My apology, due to come R&D i was using xmlElement to change name in xml the intercepted msg was intercepted after i changed my variable names. I have updated the branch Class code (which is on server side). – Kumar Gaurav Oct 24 '14 at 04:44