Paul Taylor
Paul Taylor

Reputation: 13110

JAXB generated classes from Xml schema doesnt return getter setters for all attributes

I am using Jaxb to build Java classes for marshalling xml data from the upnp didlite specification, the required xsd files can be found at https://gitlab.gnome.org/GNOME/gupnp-av/-/tree/master/data

It works but not as well as I would like some elements dont return getters and setters for most attributes or even a name/value map. Instead they just provide a list of all JAXBElements that I have to iterate through to find the attribute I want, why is that ?

/**
 * Gets the value of the allowedUnderItem property.
 * 
 * <p>
 * This accessor method returns a reference to the live list,
 * not a snapshot. Therefore any modification you make to the
 * returned list will be present inside the JAXB object.
 * This is why there is not a <CODE>set</CODE> method for the allowedUnderItem property.
 * 
 * <p>
 * For example, to add a new item, do as follows:
 * <pre>
 *    getAllowedUnderItem().add(newItem);
 * </pre>
 * 
 * 
 * <p>
 * Objects of the following type(s) are allowed in the list
 * {@link JAXBElement }{@code <}{@link ChannelGroupNameType }{@code >}
 * {@link JAXBElement }{@code <}{@link ChannelIDType }{@code >}
 * {@link JAXBElement }{@code <}{@link DayOfWeekEnLen3 }{@code >}
 * {@link JAXBElement }{@code <}{@link DescType }{@code >}
 * {@link JAXBElement }{@code <}{@link DeviceUDNType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ElementType }{@code >}
 * {@link JAXBElement }{@code <}{@link ForeignMetadataType }{@code >}
 * {@link JAXBElement }{@code <}{@link GenreType }{@code >}
 * {@link JAXBElement }{@code <}{@link InclusionType }{@code >}
 * {@link JAXBElement }{@code <}{@link ObjectLinkRefType }{@code >}
 * {@link JAXBElement }{@code <}{@link ObjectLinkType }{@code >}
 * {@link JAXBElement }{@code <}{@link OwnerType }{@code >}
 * {@link JAXBElement }{@code <}{@link PersonWithRoleType }{@code >}
 * {@link JAXBElement }{@code <}{@link PersonWithRoleType }{@code >}
 * {@link JAXBElement }{@code <}{@link PersonWithRoleType }{@code >}
 * {@link JAXBElement }{@code <}{@link PreservedTimeRangeType }{@code >}
 * {@link JAXBElement }{@code <}{@link PriceType }{@code >}
 * {@link JAXBElement }{@code <}{@link ProgramCodeType }{@code >}
 * {@link JAXBElement }{@code <}{@link ProgramIDType }{@code >}
 * {@link JAXBElement }{@code <}{@link ProgramIDType }{@code >}
 * {@link JAXBElement }{@code <}{@link ProgramListType }{@code >}
 * {@link JAXBElement }{@code <}{@link ProgramPreservedType }{@code >}
 * {@link JAXBElement }{@code <}{@link QualifiedDateTime }{@code >}
 * {@link JAXBElement }{@code <}{@link QualifiedDateTime }{@code >}
 * {@link JAXBElement }{@code <}{@link QualifiedDateTimeISO8601 }{@code >}
 * {@link JAXBElement }{@code <}{@link QualifiedDateTimeISO8601 }{@code >}
 * {@link JAXBElement }{@code <}{@link QualifiedDateTimeRange }{@code >}
 * {@link JAXBElement }{@code <}{@link RatingType }{@code >}
 * {@link JAXBElement }{@code <}{@link ResExtType }{@code >}
 * {@link JAXBElement }{@code <}{@link ResType }{@code >}
 * {@link JAXBElement }{@code <}{@link SearchClassType }{@code >}
 * {@link JAXBElement }{@code <}{@link SearchClassType }{@code >}
 * {@link JAXBElement }{@code <}{@link StateVariableCollectionType }{@code >}
 * {@link JAXBElement }{@code <}{@link StatusType }{@code >}
 * {@link JAXBElement }{@code <}{@link Boolean }{@code >}
 * {@link JAXBElement }{@code <}{@link Boolean }{@code >}
 * {@link JAXBElement }{@code <}{@link Boolean }{@code >}
 * {@link JAXBElement }{@code <}{@link Boolean }{@code >}
 * {@link JAXBElement }{@code <}{@link Integer }{@code >}
 * {@link JAXBElement }{@code <}{@link Integer }{@code >}
 * {@link JAXBElement }{@code <}{@link Integer }{@code >}
 * {@link JAXBElement }{@code <}{@link Integer }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link Long }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link String }{@code >}
 * {@link JAXBElement }{@code <}{@link List }{@code <}{@link String }{@code >}{@code >}
 * 
 * 
 */
public List<JAXBElement<?>> getAllowedUnderItem() {
    if (allowedUnderItem == null) {
        allowedUnderItem = new ArrayList<JAXBElement<?>>();
    }
    return this.allowedUnderItem;
}

meaning I have to write code like

if(object instanceof ContainerType)
        {
            id = ((ContainerType)object).getId();
            title = ((ContainerType)object).getTitle().getValue();

            Iterator<JAXBElement<?>> i = ((ContainerType)object).getAllowedUnderContainer().iterator();
            while(i.hasNext())
            {
                JAXBElement next = i.next();
                if(next.getName().getLocalPart().equals("albumArtURI"))
                {
                    albumArtistUri = (String)next.getValue();
                }
            }
}   

How can I improve this ?

Upvotes: 3

Views: 1043

Answers (2)

jccampanero
jccampanero

Reputation: 53411

Although probably difficult in this case, due to the complexity of the schema you are working with, but you could try using JAXB XML bindings for this purpose.

JAXB XML bindings allows you to customize the JAXB Java classes generation process in different ways.

Among these customizations, it allows you to instruct the generator to use your own model of classes.

This information should be provided in a bindings XML file; in your use case, it could be similar to this:

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">

    <jaxb:bindings schemaLocation="didl-lite-v2.xsd">
        <jaxb:bindings node="//xsd:complexType[@name='container.type']">
            <jaxb:class ref="didl.ContainerType"/>
        </jaxb:bindings>
        <jaxb:bindings node="//xsd:complexType[@name='item.type']">
            <jaxb:class ref="didl.ItemType"/>
        </jaxb:bindings>
    </jaxb:bindings>
</jaxb:bindings>

Note the definition of the custom classes didl.ContainerType and didl.ItemTypein order to represent the complex types container.type and item.type, respectively.

ContainerType could look like this:

package didl;

import javax.xml.bind.annotation.XmlElement;

public class ContainerType {

  @XmlElement(
      name = "title", namespace = "http://purl.org/dc/elements/1.1/"
  )
  private String title;

  @XmlElement(
      name = "albumArtURI", namespace = "urn:schemas-upnp-org:metadata-1-0/upnp/"
  )
  private String albumArtURI;

  // Other fields

  public String getTitle() {
    return title;
  }

  public String getAlbumArtURI() {
    return albumArtURI;
  }
  
  // Other getters
}

I will use the xjc tool in the answer but the solution should be easily portable to Maven, for example.

Using xjc, you need to generate your code like this to tale into account the bindings file and classes requested:

xjc -d output -b binding.xml didl-lite-v2.xsd -classpath /path/to/custom/classes

As you can see, we provided both the bindings file, binding.xml, and the classpath where the generator should search for your custom classes.

The same approach, although for simpler use cases, has been exemplified here in different questions in Stackoverflow, for example in these ones:

This Oracle article is quite dated, but it provides a good explanation about how the actual correspondence between fields happens.

Upvotes: 1

Stabak
Stabak

Reputation: 36

Please try using the following in a terminal. You should have all the required Java Beans created.

& "C:\Program Files\Java\jdk1.8.0_333\bin\xjc" -d src -p com.example https://gitlab.gnome.org/GNOME/gupnp-av/-/raw/master/data/av.xsd

What this does is uses the xjc command line tool to generate the artifacts from the supplied xsd. You can read more about it here: Using JAXB xjc tooling to generate JAXB classes from an XML schema file

Upvotes: 0

Related Questions