Adam Arold
Adam Arold

Reputation: 30538

How to name the xs:elements in the generated wsdl?

I fired up my WebServicesExplorer in my Eclipse recently and I just realized that the xs:element names generated by JAXB are not so verbose. Here is one of the sequences:

<xs:sequence>
  <xs:element minOccurs="0" name="arg0" type="xs:string" /> 
  <xs:element minOccurs="0" name="arg1" type="xs:string" /> 
  <xs:element name="arg2" type="xs:int" /> 
</xs:sequence>

generated from this file:

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class User {
    private String firstName;
    private String lastName;
    private int age;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

I'm not a JAXB expert yet, so I was wondering whether I can change those arg* named elements into something sensible, like in the POJO class?

Upvotes: 4

Views: 4491

Answers (1)

Bogdan
Bogdan

Reputation: 24590

You do not mention what web service framework you are using but the behaviour sounds similar to the JAX-WS specs, e.g. The parts in my generated wsdl have names of the form "arg0", "arg1", ... Why don't the parts (and Java generated from them) use the nice parameter names I typed into the interface definition?

Official answer: The JAX-WS spec (specifically section 3.6.1) mandates that it be generated this way. To customize the name, you have to use an @WebParam(name = "blah") annotation to specify better names. (You can use @WebResult for the return value, but you'll only see the results if you look at the XML.)

Reason: One of the mysteries of java is that abstract methods (and thus interface methods) do NOT get their parameter names compiled into them even with debug info. Thus, when the service model is built from an interface, there is no way to determine the names that were using in the original code.

If the service is built from a concrete class (instead of an interface) AND the class was compiled with debug info, we can get the parameter names. The simple frontend does this. However, this could cause potential problems. For example, when you go from developement to production, you may turn off debug information (remove -g from javac flags) and suddenly the application may break since the generated wsdl (and thus expect soap messages) would change. Thus, the JAX-WS spec writers went the safe route and mandate that you have to use the @WebParam annotations to specify the more descriptive names.

You could try adding an XmlElement annotation to each field and specify a name, but are you sure this is caused by JAXB? If I run schemagen with your POJO code this is what I get (the names are picked up correctly):

<xs:complexType name="user">
    <xs:sequence>
      <xs:element name="age" type="xs:int"/>
      <xs:element name="firstName" type="xs:string" minOccurs="0"/>
      <xs:element name="lastName" type="xs:string" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

Based on your comment, if you "force" your POJO to the following code, do you still get complaints about duplicate names?

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlAccessType;

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement
public class User {
    @XmlElement(name = "firstName")
    private String firstName;

    @XmlElement(name = "lastName")
    private String lastName;

    @XmlElement(name = "age")
    private int age;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Upvotes: 1

Related Questions