Я пытаюсь сериализовать свои данные в файл 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);
}
}
Пожалуйста, улучшите вопрос. Прочитать Как создать минимальный пример Воспроизводимый
@Andreas Извините, я, должно быть, неправильно набрал moduleArray. Меня не волнует порядок роли или moduleArray, просто пример. У студенческого класса нет поля studentArray, не могли бы вы расширить пункт 3.
Извините, moduleArray
. У класса Student
есть поле, но нет методов для него, и нигде нет свидетельств того, что вы когда-либо добавляли что-либо в этот список, поскольку вы не показали код любойвоспроизводимый для генерации фактического результата, который вы получаете.
@Andreas Добавили вызовы для добавления модуля. Из вывода консоли добавляется модуль, но когда объект сериализуется в xml, возникает проблема.
Извините, но где именно строка кода, которая добавляет модуль в список модулей студенческих объектов? Кажется, я не могу найти этот код во всем нерелевантном коде, который вы опубликовали. Пожалуйста (!) Прочтите Как создать воспроизводимый пример Минимальный.
@Andreas Прямо здесь: su.addModule (newModule);
@Andreas Есть еще файлы, и вопрос уже довольно длинный, не лучше ли прислать вам проект?
Student
не имеет метода addModule()
, так как он компилируется? --- Нет, не добавляйте код к вопросу. Уменьшать код, показывающий проблему. Я спрошу вас в третий раз, выделено, чтобы вы могли увидеть это на этот раз: ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ СЛЕДУЮЩУЮ СТАТЬЮ:Как создать пример Минимальный, Воспроизводимый. Обратите внимание на раздел «Минимальный», в котором говорится об удалении кода, который не нужен для отображения проблемы. Затем прочтите раздел «Воспроизводимый», который касается включения достаточного количества кода, чтобы мы могли его запустить.
@Andreas Да, проблема с созданием минимального примера заключается в том, что это несколько файлов (как вы видели), которые все могут быть частью проблемы. Вы хотите, чтобы я удалил файлы классов, чтобы речь шла только о чтении, записи и методе, вызывающем эти функции?
Я хотел бы, чтобы вы следовали инструкциям в разделе «Минимальные» статьи, на которую я ссылался: "2. Разделяй и властвуй. Если вы не уверены, в чем причина проблемы, начните удалять код понемногу, пока проблема не исчезнет, а затем добавьте последнюю часть обратно". Вы действительно думаете, что наличие элементов внутри элемента <Module>
имеет значение для проблемы того, что <moduleArray>
пуст? Поскольку проблема описывается как проблема создания XML из данных, созданных кодом, какое отношение метод readStudents()
имеет к проблеме? Это легко удалит половину кода.
1) В вашем классе
Student
есть@XmlElement private ModuleArrayList moduleArray = new ModuleArrayList();
, поэтому имя элемента совпадает с именем поля, то естьmoduleArray
, так почему вы ожидаете, что это будетmoduleArrayList
? --- 2) В вашем классеStudent
нет@XmlType(propOrder = {"role","moduleArray"})
, так почему вы ожидали, что элементrole
будет первым? --- 3) ПолеstudentArray
вашего классаStudent
не может быть доступно для внешнего кода Java и никогда не заполняется значениями, так почему вы ожидали, что в списке будут значения?