3

I'm trying to unmarshal an a xml file. Here's my files below.

XML file

<AccountInfo>
   <Account>
    <FirstName>FirstName1</FirstName>
    <LastName>LastName1</LastName>
    <Country>US</Country>
    <PhoneNumber>2022023111</PhoneNumber>
    <Email>test@test.com</Email>
    <Password>1222433123</Password>
    <PaymentMethod>
        <CardNumber>4111111111111111</CardNumber>
        <Month>12</Month>
        <Year>2017</Year>
        <CVV>098</CVV>
        <StreetAddress>test</StreetAddress>
        <Town>test</Town>
        <State>Virginia</State>
        <ZipCode>12365</ZipCode>
        <Country>US</Country>
    </PaymentMethod>
 </Account>
 <Account>
    <FirstName>FirstName1</FirstName>
    <LastName>LastName1</LastName>
    <Country>US</Country>
    <PhoneNumber>2022023111</PhoneNumber>
    <Email>test@test.com</Email>
    <Password>1222433123</Password>
    <PaymentMethod>
        <CardNumber>4111111111111111</CardNumber>
        <Month>12</Month>
        <Year>2017</Year>
        <CVV>098</CVV>
        <StreetAddress>test</StreetAddress>
        <Town>test</Town>
        <State>Virginia</State>
        <ZipCode>12365</ZipCode>
        <Country>US</Country>
    </PaymentMethod>
 </Account>
</AccountInfo>

JaxbHelper.java

 public static <T> T unmarshal(InputStream file, Class<T> unmarshalClass) 
 throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(unmarshalClass);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    T object = (T) jaxbUnmarshaller.unmarshal(file);
    return object;
}

AccountInfo.java

  @XmlRootElement(name = "AccountInfo")
  @XmlAccessorType(XmlAccessType.FIELD)
  @XmlSeeAlso({PaymentMethod.class})
  public class AccountInfo {

  @XmlElement(name = "FirstName")
  private String FirstName;
  @XmlElement(name = "LastName")
  private String LastName;
  @XmlElement(name = "Country")
  private String Country;
  @XmlElement(name = "PhoneNumber")
  private String PhoneNumber;
  @XmlElement(name = "Email")
  private String Email;
  @XmlElement(name = "Password")
  private String Password;
  @XmlElement(name = "PaymentMethod")
  private PaymentMethod paymentMethod;

  public AccountInfo() {
    setFirstName(null);
    setLastName(null);
    setCountry(null);
    setPhoneNumber(null);
    setEmail(null);
    setPassword(null);
    setPaymentMethod(null);
}

public AccountInfo(String FirstName, String LastName, String Country, String PhoneNumber, String Email, String Password, PaymentMethod paymentMethod) {
    setFirstName(FirstName);
    setLastName(LastName);
    setCountry(Country);
    setPhoneNumber(PhoneNumber);
    setEmail(Email);
    setPassword(Password);
    setPaymentMethod(paymentMethod);
}


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 String getCountry() {
    return Country;
}

public void setCountry(String country) {
    this.Country = country;
}

public String getPhoneNumber() {
    return PhoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
    this.PhoneNumber = phoneNumber;
}

public String getEmail() {
    return Email;
}

public void setEmail(String email) {
    this.Email = email;
}

public String getPassword() {
    return Password;
}

public void setPassword(String password) {
    this.Password = password;
}

public PaymentMethod getPaymentMethod() {
    return paymentMethod;
}


public void setPaymentMethod(PaymentMethod paymentMethod) {
    this.paymentMethod = paymentMethod;
  }
}

How I consume the unmarshal

  List<T> accountInfo = (List<T>)ProcessClassHelper.unmarshal(xmlfile, Class.forName(Constants.ClassesDir +className));

I'm unsure what's causing the issue but the object is returned as single object even though there are multiple accounts and the returned data are null.

Thanks in advance.

Mohamed Said
  • 524
  • 7
  • 27
  • Isn't your account info a list of account objects? I don't see how your AccountInfo class is reflecting that. Your AccountInfo class looks like I would model the Account class. For what I see, your model class does not fit the XML. – Rhayene May 02 '17 at 16:00
  • @Rhayene accountinfo is a root element containing accounts, so yes – Mohamed Said May 02 '17 at 16:12
  • 1
    look at this answer of [How do I parse this XML in Java with JAXB?](http://stackoverflow.com/questions/8186896/how-do-i-parse-this-xml-in-java-with-jaxb/8187505#8187505), it should give a nice example how you can parse a list. – Rhayene May 02 '17 at 16:19
  • 1
    I would look at this [blog post](http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html) or similar resources and choose the modeling that fits my XML best. – Rhayene May 02 '17 at 16:26
  • @Rhayene Thanks for your comments above, they did help for the payment method but what about the Accounts? I can't seem to parse them – Mohamed Said May 02 '17 at 16:40
  • 1
    rename your AccountInfo class to Account, create a new class AccountInfo with the attribute List accounts and look at the second example in the blog post, that should fit your XML (the one with the `@XmlElement(name="email-address")`) annotation - of course not literally. It doesn't matter if you marshall or unmarshall, the model class is the same. – Rhayene May 02 '17 at 17:10
  • @Rhayene I've done so and it's now working. thank you so much for your help! been trying for almost a week! :) – Mohamed Said May 03 '17 at 10:44

1 Answers1

5

Your Java classes don't match the structure of your XML file. As @Rhayene already commented, you need separate Java classes for AccountInfo and Account.

AccountInfo will contain only a list of Accounts:

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

    @XmlElement(name = "Account")
    private List<Account> accounts;

    // + constructors, getters, setters
}

Account will contain all the properties which you had in in AccountInfo before.
(By the way: You should also follow the convention of field names beginning with lower-case letter. This will not break anything because the XML names are still specified by @XmlElement)

@XmlAccessorType(XmlAccessType.FIELD)
public class Account {

    @XmlElement(name = "FirstName")
    private String firstName;
    @XmlElement(name = "LastName")
    private String lastName;
    @XmlElement(name = "Country")
    private String country;
    @XmlElement(name = "PhoneNumber")
    private String phoneNumber;
    @XmlElement(name = "Email")
    private String email;
    @XmlElement(name = "Password")
    private String password;
    @XmlElement(name = "PaymentMethod")
    private PaymentMethod paymentMethod;

    // + constructors, getters, setters
}
Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49