Создан неверный XML-файл JAXB

Я пытаюсь сериализовать свои данные в файл XML с помощью JAXB

Ожидаемый результат

<?xml version = "1.0" encoding = "UTF-8" standalone = "yes"?>
<Students>
    <Student id = "0">
        <role>Student</role>
        <moduleArray/>
    </Student>
    <Student id = "1">
        <role>Student</role>
        <moduleArray>
            <Module academicYear = "AY_2019_20">
                <ModuleCode>CSC1022</ModuleCode>
                <Semester>AUT</Semester>
                <Mark markVal = "100" notes = "P"/>
            </Module>
        </moduleArray>
    </Student>
    <Student id = "2">
        <role>Student</role>
        <moduleArray/>
    </Student>
    <Student id = "3">
        <role>Student</role>
        <moduleArray/>
    </Student>
    <Student id = "4">
        <role>Student</role>
        <moduleArray/>
    </Students>

Фактический выход

<?xml version = "1.0" encoding = "UTF-8" standalone = "yes"?>
<Students>
    <Student id = "0">
        <moduleArray/>
        <role>Student</role>
    </Student>
    <Student id = "1">
        <moduleArray/>
        <role>Student</role>
    </Student>
    <Student id = "2">
        <moduleArray/>
        <role>Student</role>
    </Student>
    <Student id = "3">
        <moduleArray/>
        <role>Student</role>
    </Student>
    <Student id = "4">
        <moduleArray/>
        <role>Student</role>
    </Student>
</Students>

Данные модуля не записываются в файл. Я не уверен, что могло быть не так, поскольку я делал подобное в прошлом. Вот определения классов:

отметка

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Mark")
public class Mark {
    @XmlAttribute(required=true)
    private double markVal;
    @XmlAttribute(required=false)
    private String notes;
    public Mark() {
        
    }
    public Mark(double mark_val,String notes) {
        this.markVal = mark_val;
        this.notes = notes;
    }

Модуль

package StudentManagementService;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Module")
public class Module {
    @XmlElement(name= "ModuleCode")
    private ModuleCode moduleCode;
    @XmlElement(name= "Semester")
    private Semester semester;
    @XmlAttribute(required = true)
    private String academicYear;
    @XmlElement(name= "Mark")
    private Mark mark;
    public Module() {
        
    }
    public Module(ModuleCode moduleCode,Semester semester, String academicYear) {
        this.moduleCode = moduleCode;
        this.semester = semester;
        this.academicYear = academicYear;
        //ASSUME that a created module will not have a mark assigned
        this.mark = null;
    }

ModuleArrayList

package StudentManagementService;

import java.util.ArrayList;

import javax.xml.bind.annotation.*;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Modules")
public class ModuleArrayList {
    @XmlElement(name = "Module")
    private ArrayList<Module> ModuleArray = new ArrayList<Module>();
    
    
    public ModuleArrayList() {
        
    }
    public void addModule(Module m) {
        this.ModuleArray.add(m);
    }
    //getter to return Module Array
    public ArrayList<Module> getModuleList() {
        return this.ModuleArray;
    }
    

}

Код модуля

package StudentManagementService;

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

@XmlRootElement(name = "ModuleCode")
@XmlAccessorType(XmlAccessType.FIELD)
public enum ModuleCode {
    CSC1022,CSC1023,CSC1024,CSC1025,CSC1026,CSC1027,CSC1028,CSC1029,CSC1030,CSC1031
}

Роль

package StudentManagementService;

import javax.xml.bind.annotation.*;

@XmlRootElement(name = "Role")
@XmlAccessorType(XmlAccessType.FIELD)
public enum Role {
    Student,AcademicStaff

}

Семестр

package StudentManagementService;

import javax.xml.bind.annotation.*;

@XmlRootElement(name = "Semester")
@XmlAccessorType(XmlAccessType.FIELD)
public enum Semester {
    AUT,SPR,FY
}

Ученик

package StudentManagementService;


import javax.xml.bind.annotation.*;


@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Student")
public class Student {
    @XmlElement
    private ModuleArrayList moduleArray = new ModuleArrayList();
    @XmlAttribute
    private int id;
    @XmlElement
    private Role role;
    public Student(int id) {
        this.id = id;
        this.role = Role.Student;
    }
    public Student() {
        
    }

StudentArrayList

package StudentManagementService;

import java.util.ArrayList;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Students")
public class StudentArrayList { 
        @XmlElement(name = "Student")
        private ArrayList<Student> studentArray = new ArrayList<Student>();
        public StudentArrayList() {
            
        }
        public void addEndUser(Student eu) {
            this.studentArray.add(eu);
        }
        //getter to return End User Array
        public ArrayList<Student> getStudentList() {
            return this.studentArray;
        }
}

Вот методы чтения и записи.

private void writeStudents(StudentArrayList sal) {
    // Don't need try catch as we want to rewrite.
    try {
        OutputStream outputStream = new FileOutputStream(
                "C:\\Program Files (x86)\\eclipse\\workspace\\csc2063-project-maven\\src\\main\\java\\StudentManagementService\\Students.xml");
        JAXBContext jc = JAXBContext.newInstance(StudentArrayList.class);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(sal, outputStream);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private StudentArrayList readStudents() {
    try {
        InputStream inputStream = new FileInputStream("C:\\Program Files (x86)\\eclipse\\workspace\\csc2063-project-rework1\\src\\main\\java\\StudentManagementService\\Students.xml");
        JAXBContext jc = JAXBContext.newInstance(StudentArrayList.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        StudentArrayList sal = (StudentArrayList) unmarshaller.unmarshal(inputStream);
        return sal;
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return null;

}

Во время отладки я пришел к выводу, что сериализация JAXB виновата. Что-то идет не так, когда объекты сериализуются. В этом отрывке я пытаюсь «зарегистрировать» ученика с идентификатором 1 в модуль. Ввод правильный, выходной бит неверный.

Before Insertion (Correct)
0 Modules: []
1 Modules: []
2 Modules: []
3 Modules: []
4 Modules: []

Before writing to XML (Correct)
0 Modules: []
1 Modules: [StudentManagementService.Module@1a42824]
2 Modules: []
3 Modules: []
4 Modules: []

After writing to XML (Incorrect)
0 Modules: []
1 Modules: []
2 Modules: []
3 Modules: []
4 Modules: []
Successful enrollment of the student with ID 1 on the module CSC1022, AUT, AY_2019_20 by the academic staff member with ID 5

Извините за длинный вопрос, но я считаю, что вам нужна вся эта информация для решения проблемы.

Любая помощь приветствуется.

Метод добавления модуля

Метод, используемый для добавления Module.

public int insertMarkToModule(int studentID,String moduleCodeString,String semesterString,String academicYear,double markVal,String notes) {
        Module checkModule = new Module(convertStringToModuleCode(moduleCodeString),convertStringToSemester(semesterString),academicYear);
        Mark newMark = createMark(markVal,notes);
        StudentArrayList sal = readStudents();
        for (Student su: sal.getStudentList()) {
            if (su.getID()== studentID) {
                for(Module m: su.getModules().getModuleList()) {
                    //If the module details match
                    if (m.getYear().equals(checkModule.getYear()) && m.getSemester().equals(checkModule.getSemester()) && m.getModuleCode().equals(checkModule.getModuleCode())) {
                        m.setMark(newMark);
                        //Save Changes
                        writeStudents(sal);
                        return 0;
                    }
                }
            }
        }
        return -1;
    }

Этот метод вызывается контроллером

public int enrollStudentToModule(String moduleCode, String semester, String academicYear, int idOfStudent) {
    Module newModule = new Module(convertStringToModuleCode(moduleCode),convertStringToSemester(semester),academicYear);
    StudentArrayList sal = readStudents();
    for(Student su: sal.getStudentList()) {
        System.out.println(su);
    }
    boolean found = false;
    for(Student su: sal.getStudentList()) {
        if (su.getID() == idOfStudent) {
            //Each student can enroll on one module
            if (su.getModules().getModuleList().size()<1) {
                su.addModule(newModule);
                found = true;
            }
        }
    }
    if (found==true) {
        //Save changes
        for(Student su: sal.getStudentList()) {
            System.out.println(su);
        }
        writeStudents(sal);
        StudentArrayList sale = readStudents();
        for(Student su: sale.getStudentList()) {
            System.out.println(su);
        }
        return 0;
    }
    //Not found
    return -1;
}

Этот метод вызывается CLI.

    System.out.println("2. Enrolling a student on a module");
    //Will Fail
    enrollStudentCLI(0,1,moduleCode,semester,academicYear,controller);
    //Will Fail
    enrollStudentCLI(5,7,moduleCode,semester,academicYear,controller);
    //Will Pass
    enrollStudentCLI(5,1,moduleCode,semester,academicYear,controller);
...
private static void enrollStudentCLI(int academicID,int studentID,String moduleCode,String semester,String academicYear,Controller controller) {
    //Academic Staff member with ID 2 Enrolling Student on module with ID of 1
    if (controller.enrollStudent(academicID,studentID,moduleCode,semester,academicYear)== -1) {
        System.out.println("Error enrolling student with ID "+studentID+" by the academic staff member with ID "+academicID);
    }
    else {
        System.out.println("Successful enrollment of the student with ID "+studentID+" on the module "+moduleCode+", "+semester+", "+academicYear+" by the academic staff member with ID "+academicID);
    }
}

1) В вашем классе Student есть @XmlElement private ModuleArrayList moduleArray = new ModuleArrayList();, поэтому имя элемента совпадает с именем поля, то есть moduleArray, так почему вы ожидаете, что это будет moduleArrayList? --- 2) В вашем классе Student нет @XmlType(propOrder = {"role","moduleArray"}), так почему вы ожидали, что элемент role будет первым? --- 3) Поле studentArray вашего класса Student не может быть доступно для внешнего кода Java и никогда не заполняется значениями, так почему вы ожидали, что в списке будут значения?

Andreas 03.04.2021 18:23

Пожалуйста, улучшите вопрос. Прочитать Как создать минимальный пример Воспроизводимый

Andreas 03.04.2021 18:23

@Andreas Извините, я, должно быть, неправильно набрал moduleArray. Меня не волнует порядок роли или moduleArray, просто пример. У студенческого класса нет поля studentArray, не могли бы вы расширить пункт 3.

Lyra Orwell 03.04.2021 18:34

Извините, moduleArray. У класса Student есть поле, но нет методов для него, и нигде нет свидетельств того, что вы когда-либо добавляли что-либо в этот список, поскольку вы не показали код любойвоспроизводимый для генерации фактического результата, который вы получаете.

Andreas 03.04.2021 18:36

@Andreas Добавили вызовы для добавления модуля. Из вывода консоли добавляется модуль, но когда объект сериализуется в xml, возникает проблема.

Lyra Orwell 03.04.2021 18:47

Извините, но где именно строка кода, которая добавляет модуль в список модулей студенческих объектов? Кажется, я не могу найти этот код во всем нерелевантном коде, который вы опубликовали. Пожалуйста (!) Прочтите Как создать воспроизводимый пример Минимальный.

Andreas 03.04.2021 18:51

@Andreas Прямо здесь: su.addModule (newModule);

Lyra Orwell 03.04.2021 18:58

@Andreas Есть еще файлы, и вопрос уже довольно длинный, не лучше ли прислать вам проект?

Lyra Orwell 03.04.2021 18:59
Student не имеет метода addModule(), так как он компилируется? --- Нет, не добавляйте код к вопросу. Уменьшать код, показывающий проблему. Я спрошу вас в третий раз, выделено, чтобы вы могли увидеть это на этот раз: ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ СЛЕДУЮЩУЮ СТАТЬЮ:Как создать пример Минимальный, Воспроизводимый. Обратите внимание на раздел «Минимальный», в котором говорится об удалении кода, который не нужен для отображения проблемы. Затем прочтите раздел «Воспроизводимый», который касается включения достаточного количества кода, чтобы мы могли его запустить.
Andreas 03.04.2021 19:08

@Andreas Да, проблема с созданием минимального примера заключается в том, что это несколько файлов (как вы видели), которые все могут быть частью проблемы. Вы хотите, чтобы я удалил файлы классов, чтобы речь шла только о чтении, записи и методе, вызывающем эти функции?

Lyra Orwell 03.04.2021 19:27

Я хотел бы, чтобы вы следовали инструкциям в разделе «Минимальные» статьи, на которую я ссылался: "2. Разделяй и властвуй. Если вы не уверены, в чем причина проблемы, начните удалять код понемногу, пока проблема не исчезнет, ​​а затем добавьте последнюю часть обратно". Вы действительно думаете, что наличие элементов внутри элемента <Module> имеет значение для проблемы того, что <moduleArray> пуст? Поскольку проблема описывается как проблема создания XML из данных, созданных кодом, какое отношение метод readStudents() имеет к проблеме? Это легко удалит половину кода.

Andreas 03.04.2021 22:17
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
11
27
0

Другие вопросы по теме