JAXB列表作为顶级XML

时间:2016-05-25 01:37:04

标签: java jaxb jax-rs

更新:最终我尝试了这里建议的所有内容并且似乎取得了一些进展,但我的API已经过度设计用于预期目的而且我已经没时间了,所以我切换到硬编码&#34 ;学生名单"在我的GET /学生电话的字符串响应中,这对于我需要它的概念证明来说已经足够了。

我正在开发一个简单的REST服务,它使用XML来处理学生记录。

当我对学生进行GET时,我得到了:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<students>
    <student>
        <grade>B</grade>
        <name>Jane</name>
    </student>
    ...
</students>

但是,我希望输出为:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student-list>
    <student>
        <grade>B</grade>
        <name>Jane</name>
    </student>
    ...
</student-list>

这是我的 Student.java 代码段:

@XmlRootElement(name = "student")
public class Student {
    private String name;
    private String grade;

    public Student() {
    }

    public Student(String name, String grade) {
        super();
        this.name = name;
        this.grade = grade;
    }

    // getters/setters ...

}

我尝试将XmlRootElement更改为&#34; student-list&#34;,但这会使列表中的每个子元素成为学生列表类型,并忽略顶级元素列表。

该项目使用带有StudentsResource类的JAX-RS,我尝试在该资源类上设置XmlRootElement名称,但这不影响任何输出。

它似乎是根据StudentsResource类自动命名顶级列表,我无法弄清楚如何覆盖此名称。

我一直在梳理这方面的文档,但Java现在不是我最强的语言,所以我无法理解这些部分如何适合JAXB和JAX-RS。

任何想法,或推动正确的方向?

编辑:添加了StudentsResource.java代码段

@Path("/student")
public class StudentsResource {
    // this is a mapper class
    @Context
    UriInfo uriInfo;
    @Context
    Request request;

    StudentService studentService;

    public StudentsResource() {
        studentService = new StudentService();
    }

    @GET
    @Produces("text/xml;charset=utf-8")
    public List<Student> getStudents() {
        return studentService.getStudentAsList();
    }
    ...        
}

根据Mateen Momin的反馈,我现在通过GET / student上的REST服务输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<studentDao_Students>
    <student>
        <name>Jane</name>
        <grade>B</grade>
    </student>
    ...
</studentDao_Students>

我有一个StudentDao,它被StudentService包装,最终由资源类调用,以使HTTP调用成为可能。我已将我的学生课程移到StudentDao,这让我意识到StudentService实际上正在编组,这里有更新的片段:

StudentDao.java

public enum StudentDao {
    instance;
    private Map<String, Student> students = new HashMap<String, Student>();

    private StudentDao() {

        //pre-populate for testing purposes
        Student student = new Student("John", "A");
        students.put("John", student);
        student = new Student("Jane", "B");
        students.put("Jane", student);
        student = new Student("TESTUSER", "F");
        students.put("TESTUSER", student);
    }

    public Map<String, Student> getStudents() {
        return students;
    }

    @XmlRootElement(name="student")
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Student {
        private String name;
        private String grade;

        public Student() {
        }

        public Student(String name, String grade) {
            super();
            this.name = name;
            this.grade = grade;
        }
        // getters/setters here...
    }
}

StudentService.java

@XmlRootElement(name = "student-list")
@XmlAccessorType(XmlAccessType.FIELD)
public class StudentService {

    StudentDao studentDao;

    public StudentService() {
        studentDao = StudentDao.instance;
    }
    // CRUD methods here which call the StudentDao HashMap
}

StudentsResource.java

@Path("/student")
public class StudentsResource {
    @Context
    UriInfo uriInfo;
    @Context
    Request request;

    StudentService studentService;

    public StudentsResource() {
        studentService = new StudentService();
    }

    @GET
    @Produces("text/xml;charset=utf-8")
    public List<Student> getStudents() {
        return studentService.getStudentAsList();
    }

    // other HTTP calls, POST,PUT,etc. here        
}

我创建了一个main函数来查看如果指定JAXBContext会发生什么:

主要用于测试控制台输出

public class Main {
    public static void main(String[] args) {
        StudentService studentDao = new StudentService();        

        StudentDao.Student stu1 = new StudentDao.Student();
        stu1.setName("marc");
        stu1.setGrade("A");
        StudentDao.Student stu2 = new StudentDao.Student();
        stu2.setName("jacob");
        stu2.setGrade("B");
        StudentDao.Student stu3 = new StudentDao.Student();
        stu3.setName("anthony");
        stu3.setGrade("A");

        studentDao.createStudent(stu1);
        studentDao.createStudent(stu2);
        studentDao.createStudent(stu3);


        try {

            File file = new File("out.xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(StudentService.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            jaxbMarshaller.marshal(studentDao, file);
            jaxbMarshaller.marshal(studentDao, System.out);

        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

当我运行这个main函数来查看输出时我实际上得到了这个,当然它与REST输出不匹配:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student-list>
    <studentDao>instance</studentDao>
</student-list>

这似乎很有希望,但我似乎无法在REST调用中覆盖顶级类名,这最终是我需要的。

我在这里做错了什么其他的想法?

1 个答案:

答案 0 :(得分:1)

学生班

import java.util.ArrayList;

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


@XmlRootElement(name = "student-list")
@XmlAccessorType(XmlAccessType.FIELD)
public class Students{
//students
    @XmlElement(name = "student")
    public ArrayList<Student> studentsLst;

    //getters and setters
    public ArrayList<Student> getStudentsLst() {
        return studentsLst;
    }

    public void setStudentsLst(ArrayList<Student> studentsLst) {
        this.studentsLst = studentsLst;
    }

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public static class Student {
        private String name;
        private String grade;

        public Student() {
        }

        public Student(String name, String grade) {
            super();
            this.name = name;
            this.grade = grade;
        }

        // getters/setters ...
        public String getName() {
            return name;
        }

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

        public String getGrade() {
            return grade;
        }

        public void setGrade(String grade) {
            this.grade = grade;
        }

    }

}

主要方法 / marshaller使用:

public static void main(String[] args) {
        Students.Student stu1 = new Students.Student();
        stu1.setName("marc");
        stu1.setGrade("A");
        Students.Student stu2 = new Students.Student();
        stu2.setName("jacob");
        stu2.setGrade("B");
        Students.Student stu3 = new Students.Student();
        stu3.setName("anthony");
        stu3.setGrade("A");

        ArrayList<Students.Student> studentsLst = new ArrayList<>();
        studentsLst.add(stu1);
        studentsLst.add(stu2);
        studentsLst.add(stu3);

        Students students = new Students();

        students.setStudentsLst(studentsLst);


        try {

            File file = new File("C:\\file.xml");
            JAXBContext jaxbContext = JAXBContext.newInstance(Students.class);
            Marshaller jaxbMarshaller = jaxbContext.createMarshaller();

            // output pretty printed
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

            jaxbMarshaller.marshal(students, file);
            jaxbMarshaller.marshal(students, System.out);

              } catch (JAXBException e) {
            e.printStackTrace();
              }
}

生成的输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<student-list>
    <student>
        <name>marc</name>
        <grade>A</grade>
    </student>
    <student>
        <name>jacob</name>
        <grade>B</grade>
    </student>
    <student>
        <name>anthony</name>
        <grade>A</grade>
    </student>
</student-list>

PS:由于您使用的是REST,因此上面给出的 main方法可以用于您的FYI。使用此主要方法相应地构建您的studentService.getStudentAsList()方法。 (我的假设是它几乎可以提供相同的xml。):)