From 5a3877c86b37a8e7c261166c17ad2a810708303c Mon Sep 17 00:00:00 2001 From: egor Date: Sun, 20 Mar 2022 14:33:20 +0300 Subject: [PATCH] more detailed error messages, recursion prevention, stacktrace doesn't print on error anymore, xml fix, some other minor fixes --- src/main/java/ru/erius/lab5/Lab5.java | 2 +- .../erius/lab5/collection/PeopleDatabase.java | 57 ++++++++++++------- .../lab5/commandline/CommandLineHandler.java | 22 +++---- .../commandline/PeopleDatabaseCommands.java | 3 +- .../java/ru/erius/lab5/data/Coordinates.java | 4 +- .../java/ru/erius/lab5/data/Location.java | 13 ++++- src/main/java/ru/erius/lab5/data/Person.java | 18 ++++-- .../erius/lab5/parser/CoordinateYAdapter.java | 16 ++++++ .../ru/erius/lab5/parser/HeightAdapter.java | 21 +++++++ .../ru/erius/lab5/parser/NameAdapter.java | 15 +++++ .../ru/erius/lab5/parser/PassportAdapter.java | 16 ++++++ 11 files changed, 141 insertions(+), 46 deletions(-) create mode 100644 src/main/java/ru/erius/lab5/parser/CoordinateYAdapter.java create mode 100644 src/main/java/ru/erius/lab5/parser/HeightAdapter.java create mode 100644 src/main/java/ru/erius/lab5/parser/NameAdapter.java create mode 100644 src/main/java/ru/erius/lab5/parser/PassportAdapter.java diff --git a/src/main/java/ru/erius/lab5/Lab5.java b/src/main/java/ru/erius/lab5/Lab5.java index 5b13163..cb05471 100644 --- a/src/main/java/ru/erius/lab5/Lab5.java +++ b/src/main/java/ru/erius/lab5/Lab5.java @@ -15,7 +15,7 @@ public class Lab5 { try { peopleDatabase.load(); } catch (Database.DatabaseLoadFailedException e) { - System.out.println("Не удалось загрузить коллекцию из файла"); + System.out.println(e.getMessage()); } PeopleDatabaseCommands.setPeopleDatabase(peopleDatabase); diff --git a/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java b/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java index 29553d1..3d72bb5 100644 --- a/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java +++ b/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java @@ -19,6 +19,7 @@ import java.util.TreeSet; /** * Класс базы данных людей, реализующий интерфейс Database + * * @see ru.erius.lab5.collection.Database */ @XmlRootElement @@ -33,9 +34,14 @@ public class PeopleDatabase implements Database { private JAXBContext context; @XmlTransient private File file; - @Getter @XmlElement(name = "person") + @XmlTransient + private String errorMessage; + @Getter + @XmlElement(name = "person") private TreeSet collection = new TreeSet<>(); - @Getter @XmlJavaTypeAdapter(LocalDateAdapter.class) @XmlElement(name = "initDate") + @Getter + @XmlJavaTypeAdapter(LocalDateAdapter.class) + @XmlElement(name = "initDate") private LocalDate initDate = LocalDate.now(); { @@ -50,7 +56,7 @@ public class PeopleDatabase implements Database { return String.format("Тип коллекции: %s \n" + "Дата инициализации: %s \n" + "Количество элементов: %d \n", - TYPE, this.initDate, this.collection.size()); + TYPE, this.initDate, this.collection.size()); } /** @@ -58,27 +64,35 @@ public class PeopleDatabase implements Database { * переменной окружения {@link #ENV_VAR} * * @throws Database.DatabaseLoadFailedException если переменная окружения {@link #ENV_VAR} не задана, - * файла не существует, либо отсутствуют права на запись или чтение + * файла не существует, либо отсутствуют права на запись или чтение */ @Override public void load() throws Database.DatabaseLoadFailedException { System.out.println("Инициализация коллекции из файла..."); String path = System.getenv(ENV_VAR); - if (path == null) + if (path == null) { + errorMessage = "Не найдена переменная окружения LAB5_PATH"; throw new DatabaseLoadFailedException("Не найдена переменная окружения LAB5_PATH"); - file = new File(path); + } + File file = new File(path); - if (!file.exists()) - throw new DatabaseLoadFailedException("Файл %s не был найден. Поменяйте значение переменной окружения LAB5_PATH", path); - if (!file.canRead()) - throw new DatabaseLoadFailedException("У вас нет прав на чтение файла %s", path); - if (!file.canWrite()) - throw new DatabaseLoadFailedException("У вас нет прав на запись в файл %s", path); - if (file.isFile()) - System.out.println("Файл успешно найден"); - else - file = createFile(file); + if (!file.exists()) { + errorMessage = String.format("Файл %s не был найден. Поменяйте значение переменной окружения LAB5_PATH", path); + throw new DatabaseLoadFailedException(errorMessage); + } + if (file.isDirectory()) + file = createFile(file); + if (!file.canRead()) { + errorMessage = String.format("У вас нет прав на чтение файла %s", path); + throw new DatabaseLoadFailedException(errorMessage); + } + if (!file.canWrite()) { + errorMessage = String.format("У вас нет прав на запись в файл %s", path); + throw new DatabaseLoadFailedException(errorMessage); + } + this.file = file; + System.out.println("Файл успешно найден"); try { Unmarshaller unmarshaller = context.createUnmarshaller(); @@ -87,7 +101,8 @@ public class PeopleDatabase implements Database { this.initDate = pd.initDate; System.out.println("Инициализация успешно выполнена"); } catch (JAXBException e) { - throw new DatabaseLoadFailedException("Не удалось загрузить коллекцию из файла %s", file.getPath(), e); + e.printStackTrace(); + throw new DatabaseLoadFailedException("Не удалось загрузить коллекцию из файла %s, он пуст, либо нарушена структура xml", file.getPath(), e); } } @@ -96,19 +111,19 @@ public class PeopleDatabase implements Database { * переменной окружения {@link #ENV_VAR} * * @throws Database.DatabaseSaveFailedException если переменная окружения {@link #ENV_VAR} не задана, - * файла не существует, либо отсутствуют права на запись или чтение, или если структура xml файла - * была каким-либо образом нарушена + * файла не существует, либо отсутствуют права на запись или чтение, или если структура xml файла + * была каким-либо образом нарушена */ @Override public void save() throws Database.DatabaseSaveFailedException { if (file == null || context == null) - throw new DatabaseSaveFailedException("Не удалось сохранить коллекцию"); + throw new DatabaseSaveFailedException("Не удалось сохранить коллекцию, " + errorMessage); try { Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(this, file); } catch (JAXBException e) { - throw new DatabaseSaveFailedException("Не удалось сохранить коллекцию в файл %s", file.getPath(), e); + throw new DatabaseSaveFailedException("Не удалось сохранить коллекцию в файл %s, формат xml файла был нарушен", file.getPath(), e); } } diff --git a/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java b/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java index 468e9dc..fec750c 100644 --- a/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java +++ b/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java @@ -6,6 +6,7 @@ import java.io.*; import java.util.*; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; /** * Класс обработчика командной строки, реализует шаблон проектирования Singleton, @@ -19,6 +20,7 @@ public final class CommandLineHandler { private final static CommandLineHandler instance = new CommandLineHandler(); private final Deque inputs = new LinkedList<>(); + private final Deque fileNames = new LinkedList<>(); private final List history = new LinkedList<>(); private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); private boolean isActive = false; @@ -128,7 +130,7 @@ public final class CommandLineHandler { System.out.println("Что-то пошло не так"); return; } - addNewInput(streamReader); + addNewInput(streamReader, fileName); } private void updateHistory(String command) { @@ -203,21 +205,19 @@ public final class CommandLineHandler { return transform.apply(result); } - /** - * Метод, меняющий текущий поток ввода на stream и добавляет его в очередь {@link #inputs inputs} - * - * @param reader Новый поток ввода - */ - public void addNewInput(Reader reader) { + public void addNewInput(Reader reader, String filePath) { + if (this.fileNames.contains(filePath)) { + System.err.println("Замечена рекурсия, отмена смены потока"); + return; + } + this.fileNames.add(filePath); this.reader = new BufferedReader(reader); this.inputs.add(reader); } - /** - * Метод, убирающий текущий поток ввода из очереди {@link #inputs inputs} - * и меняющий его либо на следующий в очереди поток, либо на System.in, если очередь пуста - */ public void removeInput() { + if (fileNames.size() > 0) + fileNames.removeLast(); inputs.poll(); Reader reader = inputs.isEmpty() ? new InputStreamReader(System.in) : inputs.peek(); this.reader = new BufferedReader(reader); diff --git a/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java b/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java index 5010a60..a8a9939 100644 --- a/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java +++ b/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java @@ -113,8 +113,7 @@ public final class PeopleDatabaseCommands { peopleDatabase.save(); System.out.println("Коллекция была успешно сохранена"); } catch (Database.DatabaseSaveFailedException e) { - e.printStackTrace(); - System.out.println("Не удалось сохранить коллекцию"); + System.out.println(e.getMessage()); } } diff --git a/src/main/java/ru/erius/lab5/data/Coordinates.java b/src/main/java/ru/erius/lab5/data/Coordinates.java index d843e57..8b1ffcf 100644 --- a/src/main/java/ru/erius/lab5/data/Coordinates.java +++ b/src/main/java/ru/erius/lab5/data/Coordinates.java @@ -45,9 +45,9 @@ public class Coordinates implements Comparable { * @throws IllegalArgumentException Если Y меньше или равен -816 */ public void setY(float y) { - if (y <= -816) - throw new IllegalArgumentException("Поле y класса Coordinates должно быть больше -816"); this.y = y; + if (y <= -816) + this.y = 0F; } private double distance() { diff --git a/src/main/java/ru/erius/lab5/data/Location.java b/src/main/java/ru/erius/lab5/data/Location.java index b08ab9d..0b0ece9 100644 --- a/src/main/java/ru/erius/lab5/data/Location.java +++ b/src/main/java/ru/erius/lab5/data/Location.java @@ -1,17 +1,19 @@ package ru.erius.lab5.data; import lombok.*; +import ru.erius.lab5.parser.NameAdapter; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import java.util.Comparator; /** * Класс данных местоположения, реализует сортировку по умолчанию * по имени и расстоянию до точки (0; 0; 0) */ -@Data @NoArgsConstructor @EqualsAndHashCode @ToString +@Data @EqualsAndHashCode @ToString @XmlAccessorType(XmlAccessType.FIELD) public class Location implements Comparable { @@ -31,8 +33,13 @@ public class Location implements Comparable { * Имя локации, может быть null */ @XmlElement(nillable = true) + @XmlJavaTypeAdapter(NameAdapter.class) private String name; + private Location() { + this.setName(this.name); + } + /** * Конструктор с параметрами * @@ -59,9 +66,9 @@ public class Location implements Comparable { * @throws IllegalArgumentException Если name является пустой строкой */ public void setName(String name) { - if (name != null && name.isEmpty()) - throw new IllegalArgumentException("Поле name класса Location не может быть пустым"); this.name = name; + if (name != null && name.isEmpty()) + this.name = null; } /** diff --git a/src/main/java/ru/erius/lab5/data/Person.java b/src/main/java/ru/erius/lab5/data/Person.java index 8f4f392..32c8d5c 100644 --- a/src/main/java/ru/erius/lab5/data/Person.java +++ b/src/main/java/ru/erius/lab5/data/Person.java @@ -4,7 +4,10 @@ import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NonNull; import lombok.ToString; +import ru.erius.lab5.parser.HeightAdapter; import ru.erius.lab5.parser.LocalDateAdapter; +import ru.erius.lab5.parser.NameAdapter; +import ru.erius.lab5.parser.PassportAdapter; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; @@ -35,6 +38,7 @@ public class Person implements Comparable { /** * Имя человека, не может быть null, строка не может быть пустой */ + @XmlJavaTypeAdapter(NameAdapter.class) private String name; /** * Координаты человека, не может быть null @@ -49,11 +53,13 @@ public class Person implements Comparable { * Рост человека, может быть null, значение поля должно быть больше 0 */ @XmlElement(nillable = true) + @XmlJavaTypeAdapter(HeightAdapter.class) private Integer height; /** * Номер паспорта человека, длина строки должна быть не меньше 8, поле может быть null */ @XmlElement(nillable = true) + @XmlJavaTypeAdapter(PassportAdapter.class) private String passportID; /** * Цвет глаз человека, не может быть null @@ -132,9 +138,9 @@ public class Person implements Comparable { * Если имя является пустой строкой */ public void setName(String name) { - if (name.isEmpty()) - throw new IllegalArgumentException("Поле name класса Person не может быть null или пустым"); this.name = name; + if (name.isEmpty()) + this.name = "none"; } /** @@ -145,9 +151,9 @@ public class Person implements Comparable { * @throws IllegalArgumentException Если рост меньше 0 */ public void setHeight(Integer height) { - if (height != null && height <= 0) - throw new IllegalArgumentException("Поле height класса Person должно быть больше 0"); this.height = height; + if (height != null && height <= 0) + this.height = 150; } /** @@ -158,9 +164,9 @@ public class Person implements Comparable { * @throws IllegalArgumentException Если номер паспорта меньше 8 символов в длину */ public void setPassportID(String passportID) { - if (passportID != null && passportID.length() < 8) - throw new IllegalArgumentException("Поле passportID класса Person не может быть меньше 8 символов в длину"); this.passportID = passportID; + if (passportID != null && passportID.length() < 8) + this.passportID = null; } /** diff --git a/src/main/java/ru/erius/lab5/parser/CoordinateYAdapter.java b/src/main/java/ru/erius/lab5/parser/CoordinateYAdapter.java new file mode 100644 index 0000000..cfc5386 --- /dev/null +++ b/src/main/java/ru/erius/lab5/parser/CoordinateYAdapter.java @@ -0,0 +1,16 @@ +package ru.erius.lab5.parser; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +public class CoordinateYAdapter extends XmlAdapter { + @Override + public Float unmarshal(String v) throws Exception { + float result = Float.parseFloat(v); + return result > -816F ? result : 0F; + } + + @Override + public String marshal(Float v) throws Exception { + return v.toString(); + } +} diff --git a/src/main/java/ru/erius/lab5/parser/HeightAdapter.java b/src/main/java/ru/erius/lab5/parser/HeightAdapter.java new file mode 100644 index 0000000..82778d2 --- /dev/null +++ b/src/main/java/ru/erius/lab5/parser/HeightAdapter.java @@ -0,0 +1,21 @@ +package ru.erius.lab5.parser; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +public class HeightAdapter extends XmlAdapter { + + @Override + public Integer unmarshal(String v) throws Exception { + if (v == null) + return null; + int result = Integer.parseInt(v); + if (result <= 0) + return 1; + return result; + } + + @Override + public String marshal(Integer v) throws Exception { + return v.toString(); + } +} diff --git a/src/main/java/ru/erius/lab5/parser/NameAdapter.java b/src/main/java/ru/erius/lab5/parser/NameAdapter.java new file mode 100644 index 0000000..fa318fa --- /dev/null +++ b/src/main/java/ru/erius/lab5/parser/NameAdapter.java @@ -0,0 +1,15 @@ +package ru.erius.lab5.parser; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +public class NameAdapter extends XmlAdapter { + @Override + public String unmarshal(String v) throws Exception { + return v.isEmpty() ? "none" : v; + } + + @Override + public String marshal(String v) throws Exception { + return v; + } +} diff --git a/src/main/java/ru/erius/lab5/parser/PassportAdapter.java b/src/main/java/ru/erius/lab5/parser/PassportAdapter.java new file mode 100644 index 0000000..78c0c10 --- /dev/null +++ b/src/main/java/ru/erius/lab5/parser/PassportAdapter.java @@ -0,0 +1,16 @@ +package ru.erius.lab5.parser; + +import javax.xml.bind.annotation.adapters.XmlAdapter; + +public class PassportAdapter extends XmlAdapter { + + @Override + public String unmarshal(String v) throws Exception { + return v.length() < 8 ? "no_passport" : v; + } + + @Override + public String marshal(String v) throws Exception { + return v; + } +}