【问题标题】:How do I marshall multiple objects using JAXB?如何使用 JAXB 编组多个对象?
【发布时间】:2012-09-07 18:19:35
【问题描述】:

我正在尝试编组多个对象,例如Book 通过 setBookslst() 添加到 BookLists。我开始使用这个JAXBContext 设置:

jaxbContext = JAXBContext.newInstance(BookLists.class);

 jaxbMarshaller.marshal(lists, result);

但是,我得到了以下运行时异常:

javax.xml.bind.JAXBException: com.jaxb.example.marshall.Book 也没有 它的超类在这个上下文中是已知的]

我的类型定义如下。

书:-

@XmlRootElement(name="book")
public class Book {

     private String title;
     private int year;
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public int getYear() {
        return year;
    }
    public void setYear(int year) {
        this.year = year;
    }
}

书单:-

@XmlRootElement(name="lists")
public class BookLists {
List<Book> bookslst;

public List getBookslst() {
    return bookslst;
}

public void setBookslst(List bookslst) {
    this.bookslst = bookslst;
}

}

马歇尔码:-

Book book;
    BookLists lists=new BookLists();
    List lst=new ArrayList();
    book = new Book();
    book.setTitle("Book title");
    book.setYear(2010);
    lst.add(book);
    book = new Book();
    book.setTitle("Book title1");
    book.setYear(2011);
    lst.add(book);
    lists.setBookslst(lst);
    JAXBContext jaxbContext;
    try {
        jaxbContext = JAXBContext.newInstance(BookLists.class);
        Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        StringWriter result = new StringWriter();

        jaxbMarshaller.marshal(lists, result);
        String xml = result.toString();
        System.out.println(xml);
    } catch (JAXBException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

我正在尝试添加 @XMLSeeAlso 注释(参考:- JAXB Exception: Class not known to this context)。我的版本中没有此注释。

【问题讨论】:

  • 既然可以使用 books 或 booksList ,为什么还要调用属性 bookslst。 Bookslst 看起来很懒惰。

标签: java web-services jaxb


【解决方案1】:

默认情况下,JAXB (JSR-222) 实现会检查公共访问器方法。您可以在 get/set 方法中的 List 上添加 Book 参数。

public List<Book> getBookslst() {
    return bookslst;
}

public void setBookslst(List<Book> bookslst) {
    this.bookslst = bookslst;
}

或者,您可以使用 @XmlElement 注释指定属性的类型:

@XmlElement(type=Book.class)
public List getBookslst() {
    return bookslst;
}

您还可以指定您的 JAXB 实现自省字段而不是属性:

@XmlRootElement(name="lists")
@XmlAccessorType(XmlAccessType.FIELD)
public class BookLists {
    List<Book> bookslst;
}

更新

有没有其他方法可以添加 List 而不是 BookList Marshallar.Marshall?

您可以创建一个利用@XmlAnyElement(lax=true) 注释的通用列表包装对象(请参阅:http://blog.bdoughan.com/2010/08/using-xmlanyelement-to-build-generic.html)。然后它冷处理任何带有@XmlRootElement 注释的List

列表

package forum12323397;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.*;

@XmlRootElement
public class Lists<VALUE> {

    private List<VALUE> values = new ArrayList<VALUE>();

    @XmlAnyElement(lax=true)
    public List<VALUE> getValues() {
        return values;
    }

}

演示

package forum12323397;

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Lists.class, Book.class);

        Lists<Book> lists = new Lists<Book>();

        Book book1 = new Book();
        book1.setTitle("A Book");
        book1.setYear(2001);
        lists.getValues().add(book1);

        Book book2 = new Book();
        book2.setTitle("Another Book");
        book2.setYear(2007);
        lists.getValues().add(book2);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(lists, System.out);
    }

}

输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<lists>
    <book>
        <title>A Book</title>
        <year>2001</year>
    </book>
    <book>
        <title>Another Book</title>
        <year>2007</year>
    </book>
</lists>

【讨论】:

  • 谢谢。我已经在 BookList bean 中指定了 List bookslst。但是我没有得到任何编译时异常。那么为什么要放置 setBookslst(List bookslst) 和 List getBookslst()?.
  • @user1357722 - 因为默认情况下,您的 JAXB impl 将内省公共 get/set 方法。由于您将它们作为 List 您的 JAXB (JSR-222) impl 对 Book 类一无所知。我已经用更多信息更新了我的答案。
  • 是的。我看到了更新的答案。有没有其他方法可以在 Marshallar.Marshall 中添加 List 而不是 BookList?
  • @user1357722 - 我已更新我的答案以包含不同的方法。
【解决方案2】:

我有一个工作示例:

1) XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<bookstore>
    <bookList>
        <book>
            <author>Neil Strauss</author>
            <title>The Game</title>
            <publisher>Harpercollins</publisher>
            <isbn>978-0060554736</isbn>
        </book>
        <book>
            <author>Charlotte Roche</author>
            <title>Feuchtgebiete</title>
            <publisher>Dumont Buchverlag</publisher>
            <isbn>978-3832180577</isbn>
        </book>
    </bookList>
    <location>Frankfurt Airport</location>
    <name>Fraport Bookstore</name>
</bookstore>

2) Java 类:

书店

package jaxbtest;

import java.util.ArrayList;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="bookstore") // (namespace = "de.vogella.xml.jaxb.model", name="bookstore")
public class Bookstore {

  // XmLElementWrapper generates a wrapper element around XML representation
  @XmlElementWrapper(name = "bookList")
  // XmlElement sets the name of the entities
  @XmlElement(name = "book")
  private ArrayList<Book> bookList;
  private String name;
  private String location;

  public void setBookList(ArrayList<Book> bookList) {
    this.bookList = bookList;
  }

  public ArrayList<Book> getBooksList() {
    return bookList;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getLocation() {
    return location;
  }

  public void setLocation(String location) {
    this.location = location;
  }
} 

3) 书籍

package jaxbtest;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "book")
// If you want you can define the order in which the fields are written
// Optional
@XmlType(propOrder = { "author", "name", "publisher", "isbn" })
public class Book {

  private String name;
  private String author;
  private String publisher;
  private String isbn;

  // If you like the variable name, e.g. "name", you can easily change this
  // name for your XML-Output:
  @XmlElement(name = "title")
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getAuthor() {
    return author;
  }

  public void setAuthor(String author) {
    this.author = author;
  }

  public String getPublisher() {
    return publisher;
  }

  public void setPublisher(String publisher) {
    this.publisher = publisher;
  }

  public String getIsbn() {
    return isbn;
  }

  public void setIsbn(String isbn) {
    this.isbn = isbn;
  }

} 

4) 主要

package jaxbtest;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class BookMain {

  private static final String BOOKSTORE_XML = "./bookstore-jaxb.xml";

  public static void main(String[] args) throws JAXBException, IOException {

    ArrayList<Book> bookList = new ArrayList<Book>();

    // create books
    Book book1 = new Book();
    book1.setIsbn("978-0060554736");
    book1.setName("The Game");
    book1.setAuthor("Neil Strauss");
    book1.setPublisher("Harpercollins");
    bookList.add(book1);

    Book book2 = new Book();
    book2.setIsbn("978-3832180577");
    book2.setName("Feuchtgebiete");
    book2.setAuthor("Charlotte Roche");
    book2.setPublisher("Dumont Buchverlag");
    bookList.add(book2);

    // create bookstore, assigning book
    Bookstore bookstore = new Bookstore();
    bookstore.setName("Fraport Bookstore");
    bookstore.setLocation("Frankfurt Airport");
    bookstore.setBookList(bookList);

    // create JAXB context and instantiate marshaller
    JAXBContext context = JAXBContext.newInstance(Bookstore.class);
    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

    // Write to System.out
    m.marshal(bookstore, System.out);

    // Write to File
    m.marshal(bookstore, new File(BOOKSTORE_XML));

    // get variables from our xml file, created before
    System.out.println();
    System.out.println("Output from our XML File: ");
    Unmarshaller um = context.createUnmarshaller();
    Bookstore bookstore2 = (Bookstore) um.unmarshal(new FileReader(BOOKSTORE_XML));
    ArrayList<Book> list = bookstore2.getBooksList();
    for (Book book : list) {
      System.out.println("Book: " + book.getName() + " from "
          + book.getAuthor());
    }

      /*
      String xmlStr = readFileToString(BOOKSTORE_XML);
      Bookstore bookstore = getPartial3(Bookstore.class ,xmlStr);
      for (Book b : bookstore.getBooksList())
          System.out.println(b.getName()+ " ---- " + b.getAuthor() );
       xmlStr = readFileToString("./listApplianceOfferings.xml");
      ApplianceList bookstore1 = getPartial3(ApplianceList.class ,xmlStr);
      for (Appliance b : bookstore1.getBooksList())
          System.out.println(b.getName() + " ---- " + b.getDescription() );
    */
      //88888
      // String xmlStr = readFileToString("./listStorageOfferings.xml");
//    StorageOfferings storageOfferingsList = jaxbXmlString2Class(StorageOfferings.class ,xmlStr);
      StorageOfferings storageOfferingsList = jaxbXmlFile2Class(StorageOfferings.class ,"./listStorageOfferings.xml");
      for (StorageOffering s : storageOfferingsList.getStorageOfferingList() )
          System.out.println("8888--> "+ s.getName() + " ---- " + s.getId() );
      //99999
  }//main



private static void getPartial() {
    // get variables from our xml file, created before
    System.out.println();
    System.out.println("Output from our XML File: ");
    Unmarshaller um;
    try {
        JAXBContext context = JAXBContext.newInstance(Bookstore.class);;
        um = context.createUnmarshaller();
//      um.setEventHandler(new DefaultValidationEventHandler());
        FileReader fileReader = new FileReader(BOOKSTORE_XML);
    Bookstore bookstore = (Bookstore) um.unmarshal(fileReader );
    ArrayList<Book> list = bookstore.getBooksList();
    for (Book book : list) {
      System.out.println("Book: " + book.getName() + " from "
          + book.getAuthor());
    }
    } catch (Exception e) {
        e.printStackTrace();
    }

}
private static void getPartial1() {
    // get variables from our xml file, created before
    System.out.println();
    System.out.println("Output from our XML File: ");
    Unmarshaller um;
    try {
        JAXBContext context = JAXBContext.newInstance(ApplianceList.class);;
        um = context.createUnmarshaller();
//      um.setEventHandler(new DefaultValidationEventHandler());
        FileReader fileReader = new FileReader("./listApplianceOfferings.xml");
        ApplianceList alist = (ApplianceList) um.unmarshal(fileReader );
    ArrayList<Appliance> list = alist.getBooksList();
    for (Appliance book : list) {
      System.out.println("appliance: " + book.getName() + " from "
          + book.getDescription());
    }
    } catch (Exception e) {
        e.printStackTrace();
    }

}
//-------------------
private static <T> T getPartial2(Class<T> cls, String fname) {
    // get variables from our xml file, created before
    System.out.println();
    System.out.println("Output from our XML File: ");
    Unmarshaller um;
    T alist = null;
    try {
        JAXBContext context = JAXBContext.newInstance(cls);;
        um = context.createUnmarshaller();
//      um.setEventHandler(new DefaultValidationEventHandler());
        FileReader fileReader = new FileReader(fname);
        alist = (T) um.unmarshal(fileReader );
        //ArrayList<?> list = alist.getBooksList();
//    for (Appliance book : list) {
//      System.out.println("appliance: " + book.getName() + " from "
//          + book.getDescription());
//    }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return alist;

}
//-------------------
private static <T> T jaxbXmlFile2Class(Class<T> cls, String fileName) {
        FileReader fr = null;
        char [] cbuf = null;
        try {
            fr = new FileReader(fileName);

        cbuf = new char[3000];
        Arrays.fill(cbuf, ' ');
        fr.read(cbuf);
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            try { fr.close(); } 
            catch (IOException e) {
                e.printStackTrace();
            }
        }
        String s = new String(cbuf);
        return jaxbXmlString2Class(cls, s);
    }
@SuppressWarnings("unchecked")
private static <T> T jaxbXmlString2Class(Class<T> cls, String xmlStr) {
  // get variables from our xml file, created before
  System.out.println();
  System.out.println("Output from our XML File: ");
  Unmarshaller um;
  T alist = null;
    try {
        JAXBContext context = JAXBContext.newInstance(cls);;
        um = context.createUnmarshaller();
        System.out.println(xmlStr);
        InputStream is = new ByteArrayInputStream(xmlStr.getBytes());
        alist = (T) um.unmarshal( is );
    } catch (Exception e) {
        e.printStackTrace();
    }
    return alist;

}
} 

【讨论】:

    【解决方案3】:

    使用

    List<Book> lst=new ArrayList<Book>();
    

    而不是:

    List lst=new ArrayList();
    

    同时定义 BoolList 如下:

    @XmlRootElement(name="lists")
    public class BookLists {
    List<Book> bookslst;
    
    public List<Book> getBookslst() {
        return bookslst;
    }
    
    public void setBookslst(List<Book> bookslst) {
        this.bookslst = bookslst;
    }
    
    }
    

    【讨论】:

      【解决方案4】:

      尝试将这两个类都添加到您的 JAXBContext.newInstance 调用中。

      JAXBContext.newInstance(BookLists.class, Book.class);
      

      使用你的类这行得通:

      public static void main(String [] args) throws JAXBException {
          BookLists books = new BookLists();
      
          String [] titles = {"To Kill a Mockingbird", "Twelve Angry Men", "Are You My Mother", "Green Eggs And Ham"};
      
          List<Book> list = new ArrayList<Book>();
          for (String title : titles) {
              Book book = new Book();
              book.setTitle(title);
              list.add(book);
          }
          books.setBookslst(list);
      
          JAXBContext jc = JAXBContext.newInstance(BookLists.class, Book.class);
          Marshaller nm = jc.createMarshaller();
          nm.setProperty("jaxb.formatted.output", true);
          nm.marshal(books, System.out);
      
      }
      

      输出:

      <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
      <lists>
      <book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="book">
          <title>To Kill a Mockingbird</title>
          <year>0</year>
      </book>
      <book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="book">
          <title>Twelve Angry Men</title>
          <year>0</year>
      </book>
      <book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="book">
          <title>Are You My Mother</title>
          <year>0</year>
      </book>
      <book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="book">
          <title>Green Eggs And Ham</title>
          <year>0</year>
      </book>
      </lists>
      

      【讨论】:

      • 这将使JAXBContext 知道Book 类,但JAXB 实现不会知道bookslst 属性是List&lt;Book&gt;,它将映射为List&lt;Object&gt;
      • @Blaise,它仍然有效。输出具有 xmlns 属性并且很难看。添加 类型以便映射更好。
      【解决方案5】:

      添加注解@XmlSeeAlso(value = {Book.class }) 到 BookList 类。现在应该可以工作了。

      【讨论】:

        【解决方案6】:

        实际输出:

        <lists>
            <book>
                <title>A Book</title>
                <year>2001</year>
            </book>
            <book>
                <title>Another Book</title>
                <year>2007</year>
            </book>
        </lists>
        

        预期输出:

        <lists>
            <book>
                <title>A Book</title>
                <year>2001</year>
                <title>Another Book</title>
                <year>2007</year>
            </book>
        </lists>
        

        积极寻找建议。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-27
          • 2023-03-23
          • 2013-06-09
          • 1970-01-01
          • 1970-01-01
          • 2014-05-04
          • 1970-01-01
          相关资源
          最近更新 更多