javax.xml.bind.JAXBException: class java.util.ArrayList 其任何超 class 在此上下文中都不为人所知

javax.xml.bind.JAXBException: class java.util.ArrayList nor any of its super class is known to this context

我正在编写一个 MVC Java 程序,使用 JAXB 生成 XML 并发送到显示器 jsp。 代码运行并且 XML 在浏览器中正确显示,但我仍然在 IDE 控制台中收到 JAXBException。

我已经参考了关于该主题的几页 here and here。我已经按照建议添加了 JAXB 注释,但错误并没有消失。

有人能帮忙吗?

Web Servlet

@WebServlet(name = "GetAllFilms", value = "/GetAllFilms")
public class GetAllFilms extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setCharacterEncoding("UTF-8");
        String jspDisplayString = "";

        String dataFormat = request.getParameter("format");
        if (dataFormat == null) dataFormat = "json";

        FilmDAO filmDAO = new FilmDAO();
        ArrayList<Film> allFilms = filmDAO.getAllFilms();

        request.setAttribute("films", allFilms);

        String viewJspFilePath = "";

        if (dataFormat.equals("json")) {
            response.setContentType("application/json");
            viewJspFilePath = "/WEB-INF/results/films-json.jsp";

            jspDisplayString = jsonGenerator(allFilms);

        } else if (dataFormat.equals("xml")) {
            response.setContentType("text/xml");
            viewJspFilePath = "/WEB-INF/results/films-xml.jsp";

            try {
                jspDisplayString = xmlGenerator(allFilms);
            } catch (JAXBException e) {
                e.printStackTrace();
            }

        } else {
            response.setContentType("text/plain");
            viewJspFilePath = "/WEB-INF/results/films-string.jsp";

            jspDisplayString = stringGenerator(allFilms);
        }

        RequestDispatcher dispatcher =
                request.getRequestDispatcher(viewJspFilePath);
        dispatcher.include(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    private String xmlGenerator(ArrayList<Film> allFilms)
            throws JAXBException, FileNotFoundException {

        FilmList filmList = new FilmList();
        filmList.setFilmList(allFilms);

        JAXBContext jaxbContext = JAXBContext.newInstance(FilmList.class);
        Marshaller marshaller = jaxbContext.createMarshaller();

        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

        StringWriter stringWriter = new StringWriter();
        marshaller.marshal(allFilms, stringWriter);

        return stringWriter.toString();
    }
}

电影模型Class(带有 JAXB 注释)

package model_beans;

@XmlRootElement(name = "film")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder = { "id", "title", "year", "director", "stars", "review" })

public class Film {

    public Film() {

    }

    public Film(int id, String title, int year, String director, String stars,
                String review) {
        super();
        this.id = id;
        this.title = title;
        this.year = year;
        this.director = director;
        this.stars = stars;
        this.review = review;
    }

    int id;
    String title;
    int year;
    String director;
    String stars;
    String review;

    *getters / setters excluded for ease of reading*

    @Override
    public String toString() {
        return "Film [id=" + id + ", title=" + title + ", year=" + year
                + ", director=" + director + ", stars=" + stars + ", review="
                + review + "]";
    }
}

FilmList 模型Class(带有 JAXB 注释)

package model_beans;

@XmlRootElement(namespace = "model_beans")
@XmlAccessorType(XmlAccessType.FIELD)
public class FilmList {

    @XmlElementWrapper(name = "filmList")
    @XmlElement(name = "film")
    private ArrayList<Film> filmList;

    public ArrayList<Film> getFilmList() {
        return filmList;
    }

    public void setFilmList(ArrayList<Film> filmList) {
        this.filmList = filmList;
    }
}

JSP Xml 数据格式

<?xml version="1.0" encoding="UTF-8"?>
<%--@elvariable id="films" type="model_beans.Film"--%>
<%@taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core"%>
<films>
  <headings>
    <heading>Film ID</heading>
    <heading>Title</heading>
    <heading>Year</heading>
    <heading>Director</heading>
    <heading>Stars</heading>
    <heading>Review</heading>
  </headings>
  <c:forEach items="${films}" var="f">
    <film>
      <id>${f.id}</id>
      <title>${f.title}</title>
      <year>${f.year}</year>
      <director>${f.director}</director>
      <stars>${f.stars}</stars>
      <review>${f.review}</review>
    </film>
  </c:forEach>
</films>

堆栈跟踪

javax.xml.bind.JAXBException: class java.util.ArrayList nor any of its super class is known to this context.
    at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:567)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:467)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:116)
    at controller_servlets.GetAllFilms.xmlGenerator(GetAllFilms.java:125)
    at controller_servlets.GetAllFilms.doGet(GetAllFilms.java:68)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)

修改FilmListclass如下,

  1. @XmlRootElement 注释添加到 class
  2. 从 class
  3. 中删除 @XmlElementWrapper 注释

FilmList.java

    @XmlRootElement(name="filmList")
    public class FilmList {

        private ArrayList<Film> listFilm;

        @XmlElement(name = "film")
        public ArrayList<Film> getFilmList() {
            return listFilm;
        }

        public void setFilmList(ArrayList<Film> listFilm) {
            this.listFilm = listFilm;
        }
    }

Film.java

@XmlRootElement(name = "film")
@XmlType(propOrder = { "id", "title", "year", "director", "stars", "review" })
public class Film {

    public Film() {

    }

    public Film(int id, String title, int year, String director, String stars,
                String review) {
        super();
        this.id = id;
        this.title = title;
        this.year = year;
        this.director = director;
        this.stars = stars;
        this.review = review;
    }

    int id;
    String title;
    int year;
    String director;
    String stars;
    String review;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }

    public String getDirector() {
        return director;
    }

    public void setDirector(String director) {
        this.director = director;
    }

    public String getStars() {
        return stars;
    }

    public void setStars(String stars) {
        this.stars = stars;
    }

    public String getReview() {
        return review;
    }

    public void setReview(String review) {
        this.review = review;
    }

    @Override
    public String toString() {
        return "Film [id=" + id + ", title=" + title + ", year=" + year
                + ", director=" + director + ", stars=" + stars + ", review="
                + review + "]";
    }
}

Marshaller.java

public class Marshaller {

    public static void main(String[] args) {
    
        ArrayList<Film> listFilm = new ArrayList<>();
        StringWriter stringWriter = new StringWriter();
        FilmList filmList = new FilmList();

        Film film = new Film();
        film.setDirector("a");
        film.setId(1);
        film.setReview("b");
        film.setStars("c");
        film.setTitle("e");
        film.setYear(2020);
        listFilm.add(film);
        filmList.setFilmList(listFilm);
    
        try {
            JAXBContext jaxbContext = JAXBContext.newInstance(FilmList.class);
            javax.xml.bind.Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
            jaxbMarshaller.setProperty(javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT, true);
            jaxbMarshaller.marshal(filmList, stringWriter);
        } catch (JAXBException e) {
            e.printStackTrace();
        }
        System.out.println(stringWriter);
    }
}

输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<filmList>
    <film>
        <id>1</id>
        <title>e</title>
        <year>2020</year>
        <director>a</director>
        <stars>c</stars>
        <review>b</review>
    </film>
</filmList>

已编辑

出现以下错误的原因是 @XmlRootElementArrayList<Film> 使用了相同的名称 (filmList)。因此,请将 ArrayList<Film> 的名称更改为 listFilm

注意。请设置@XmlElement注解获取方法

最后编辑

在上面的 servlet 中,您尝试在 xmlGenerator 方法中编组 java 集合(电影列表 (allFilms))。

marshaller.marshal(allFilms, stringWriter);

但无法编组集合,并且 java 集合 class 没有 JAXB 注释。

在您的例子中,创建了 FilmList 对象,但它不用于编组。我认为这是你的错误。请编组 filmList 如下

marshaller.marshal(filmList, stringWriter);