diff --git a/Package lab5.png b/Package lab5.png index 339c14c..235a95a 100644 Binary files a/Package lab5.png and b/Package lab5.png differ diff --git a/build.gradle.kts b/build.gradle.kts index 7ec3efd..16db861 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,7 +3,7 @@ plugins { } group = "ru.erius" -version = "1.1" +version = "1.2" val mainClass = "$group.${name.toLowerCase()}.$name" repositories { diff --git a/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java b/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java index df8f508..b3e1e30 100644 --- a/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java +++ b/src/main/java/ru/erius/lab5/collection/PeopleDatabase.java @@ -16,6 +16,7 @@ import java.io.File; import java.io.IOException; import java.time.LocalDate; import java.util.TreeSet; +import java.util.stream.Collectors; /** * Класс базы данных людей, реализующий интерфейс Database @@ -34,8 +35,6 @@ public class PeopleDatabase implements Database { private JAXBContext context; @XmlTransient private File file; - @XmlTransient - private String errorMessage; @Getter @XmlElement(name = "person") private TreeSet collection = new TreeSet<>(); @@ -85,14 +84,10 @@ public class PeopleDatabase implements Database { } if (file.isDirectory()) file = createFile(file); - if (!file.canRead()) { - errorMessage = String.format("У вас нет прав на чтение файла %s", file.getAbsolutePath()); - throw new DatabaseLoadFailedException(errorMessage); - } - if (!file.canWrite()) { - errorMessage = String.format("У вас нет прав на запись в файл %s", file.getAbsolutePath()); - throw new DatabaseLoadFailedException(errorMessage); - } + if (!file.canRead()) + throw new DatabaseLoadFailedException("У вас нет прав на чтение файла %s", file.getAbsolutePath()); + if (!file.canWrite()) + throw new DatabaseLoadFailedException("У вас нет прав на запись в файл %s", file.getAbsolutePath()); this.file = file; try { @@ -117,15 +112,13 @@ public class PeopleDatabase implements Database { @Override public void save() throws Database.DatabaseSaveFailedException { if (!file.exists()) { - System.out.println("Файла " + file.getAbsolutePath() + " не существует, "); - boolean created; + System.out.println("Файла " + file.getAbsolutePath() + " не существует, возможно он был удален, пытаюсь воссоздать файл..."); try { - created = file.createNewFile(); + file.createNewFile(); + System.out.println("Файл был успешно создан"); } catch (IOException e) { - + throw new DatabaseSaveFailedException("Не удается создать файл заново, пожалуйста, сделайте это вручную и попробуйте еще раз"); } - errorMessage = "Файла %s не существует, возможно он был удален"; - throw new DatabaseSaveFailedException(errorMessage, file.getAbsolutePath()); } try { Marshaller marshaller = context.createMarshaller(); @@ -154,9 +147,9 @@ public class PeopleDatabase implements Database { @Override public String toString() { - StringBuilder sb = new StringBuilder("PeopleDatabase(\n"); - this.collection.forEach(p -> sb.append("\t").append(p).append("\n")); - sb.append(")"); - return sb.toString(); + String result = "PeopleDatabase("; + result += this.collection.stream().map(Person::toString).collect(Collectors.joining(", ")); + result += ")"; + return result; } } diff --git a/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java b/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java index fec750c..bd5a604 100644 --- a/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java +++ b/src/main/java/ru/erius/lab5/commandline/CommandLineHandler.java @@ -6,7 +6,6 @@ import java.io.*; import java.util.*; import java.util.function.Function; import java.util.function.Predicate; -import java.util.stream.Collectors; /** * Класс обработчика командной строки, реализует шаблон проектирования Singleton, diff --git a/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java b/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java index a8a9939..36c1903 100644 --- a/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java +++ b/src/main/java/ru/erius/lab5/commandline/PeopleDatabaseCommands.java @@ -66,7 +66,8 @@ public final class PeopleDatabaseCommands { } public static void show(PeopleDatabase peopleDatabase) { - System.out.println(peopleDatabase); + System.out.println("Элементы коллекции:\n"); + peopleDatabase.getCollection().forEach(p -> System.out.println(p.formatted())); } public static void add(PeopleDatabase peopleDatabase) { diff --git a/src/main/java/ru/erius/lab5/data/Coordinates.java b/src/main/java/ru/erius/lab5/data/Coordinates.java index a8ef08e..65cd756 100644 --- a/src/main/java/ru/erius/lab5/data/Coordinates.java +++ b/src/main/java/ru/erius/lab5/data/Coordinates.java @@ -10,7 +10,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; /** * Класс данных координат */ -@Data @NoArgsConstructor @EqualsAndHashCode @ToString +@Data @EqualsAndHashCode @ToString @XmlAccessorType(XmlAccessType.FIELD) public class Coordinates implements Comparable { @@ -24,13 +24,16 @@ public class Coordinates implements Comparable { @XmlJavaTypeAdapter(Adapters.CoordinateYAdapter.class) private Float y; + private Coordinates() { + this.x = Adapters.DEFAULT_COORDINATE; + this.y = (float) Adapters.DEFAULT_COORDINATE; + } + /** * Конструктор с параметрами * * @param x Координата X * @param y Координата Y - * - * @throws IllegalArgumentException Если Y меньше или равен -816 */ public Coordinates(float x, float y) { this.x = x; @@ -41,13 +44,11 @@ public class Coordinates implements Comparable { * Сеттер для поля y * * @param y Координата Y - * - * @throws IllegalArgumentException Если Y меньше или равен -816 */ public void setY(float y) { this.y = y; if (y <= -816) - this.y = 0F; + this.y = (float) Adapters.DEFAULT_COORDINATE; } 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 92a546d..20d4b28 100644 --- a/src/main/java/ru/erius/lab5/data/Location.java +++ b/src/main/java/ru/erius/lab5/data/Location.java @@ -6,7 +6,6 @@ import ru.erius.lab5.parser.Adapters; 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; /** @@ -16,7 +15,6 @@ import java.util.Comparator; @Data @EqualsAndHashCode @ToString @XmlAccessorType(XmlAccessType.FIELD) public class Location implements Comparable { - /** * Координата X типа double */ @@ -26,18 +24,20 @@ public class Location implements Comparable { */ private float y; /** - * Координата Z типа Long, не может быть null + * Координата Z типа long, не может быть null */ - private Long z; + private long z; /** * Имя локации, может быть null */ @XmlElement(nillable = true) - @XmlJavaTypeAdapter(Adapters.NameAdapter.class) private String name; private Location() { - this.setName(this.name); + this.x = Adapters.DEFAULT_COORDINATE; + this.y = Adapters.DEFAULT_COORDINATE; + this.z = Adapters.DEFAULT_COORDINATE; + this.name = Adapters.DEFAULT_NAME; } /** @@ -48,11 +48,9 @@ public class Location implements Comparable { * @param z Координата Z * @param name Имя локации * - * @throws IllegalArgumentException будет брошено, если name является пустой строкой - * * @throws NullPointerException будет брошено в случае, если Z является null */ - public Location(double x, float y, @NonNull Long z, String name) { + public Location(double x, float y, long z, String name) { this.x = x; this.y = y; this.z = z; @@ -62,13 +60,11 @@ public class Location implements Comparable { /** * Сеттер для поля name * @param name Имя локации - * - * @throws IllegalArgumentException Если name является пустой строкой */ public void setName(String name) { this.name = name; if (name != null && name.isEmpty()) - this.name = null; + this.name = Adapters.DEFAULT_NAME; } /** diff --git a/src/main/java/ru/erius/lab5/data/Person.java b/src/main/java/ru/erius/lab5/data/Person.java index 599e977..998cf69 100644 --- a/src/main/java/ru/erius/lab5/data/Person.java +++ b/src/main/java/ru/erius/lab5/data/Person.java @@ -60,10 +60,12 @@ public class Person implements Comparable { /** * Цвет глаз человека, не может быть null */ + @XmlJavaTypeAdapter(Adapters.ColorAdapter.class) private Color eyeColor; /** * Национальность человека, не может быть null */ + @XmlJavaTypeAdapter(Adapters.CountryAdapter.class) private Country nationality; /** * Местоположение человека, может быть null @@ -75,6 +77,14 @@ public class Person implements Comparable { */ private Person() { this.id = ++existingPeople; + this.creationDate = Adapters.DEFAULT_DATE; + this.name = Adapters.DEFAULT_NAME; + this.coordinates = Adapters.DEFAULT_COORDINATES; + this.height = Adapters.DEFAULT_HEIGHT; + this.passportID = Adapters.DEFAULT_PASSPORT; + this.eyeColor = Adapters.DEFAULT_COLOR; + this.nationality = Adapters.DEFAULT_COUNTRY; + this.location = Adapters.DEFAULT_LOCATION; } /** @@ -88,14 +98,9 @@ public class Person implements Comparable { * @param nationality Национальность человека * @param location Местоположение человека * - * @throws IllegalArgumentException Если: - * name является пустой строкой, - * height меньше 0, - * Длина passportID меньше 8 символов - * - * @throws NullPointerException Если coordinates, eyeColor или nationality являются null + * @throws NullPointerException Если name, coordinates, eyeColor или nationality являются null */ - public Person(String name, @NonNull Coordinates coordinates, Integer height, String passportID, + public Person(@NonNull String name, @NonNull Coordinates coordinates, Integer height, String passportID, @NonNull Color eyeColor, @NonNull Country nationality, Location location) { this.id = ++existingPeople; this.creationDate = LocalDate.now(); @@ -129,40 +134,54 @@ public class Person implements Comparable { * * @param name * Имя человека - * - * @throws IllegalArgumentException - * Если имя является пустой строкой */ public void setName(String name) { this.name = name; if (name.isEmpty()) - this.name = "none"; + this.name = Adapters.DEFAULT_NAME; } /** * Сеттер для поля height * * @param height Рост человека - * - * @throws IllegalArgumentException Если рост меньше 0 */ public void setHeight(Integer height) { this.height = height; if (height != null && height <= 0) - this.height = 150; + this.height = Adapters.DEFAULT_HEIGHT; } /** * Сеттер для поля passportID * * @param passportID Номер паспорта человека - * - * @throws IllegalArgumentException Если номер паспорта меньше 8 символов в длину */ public void setPassportID(String passportID) { this.passportID = passportID; if (passportID != null && passportID.length() < 8) - this.passportID = null; + this.passportID = Adapters.DEFAULT_PASSPORT; + } + + public String formatted() { + return String.format("Человек %s:\n" + + "\tИмя: %s\n" + + "\tДата создания: %s\n" + + "\tРост: %s\n" + + "\tНомер паспорта: %s\n" + + "\tЦвет глаз: %s\n" + + "\tНациональность: %s\n" + + "\tМестоположение:\n" + + "\t\tНазвание: %s\n" + + "\t\tX: %s\n" + + "\t\tY: %s\n" + + "\t\tZ: %s\n" + + "\tКоординаты:\n" + + "\t\tX: %s\n" + + "\t\tY: %s\n", + id, name, creationDate, height, passportID, eyeColor, nationality, + location.getName(), location.getX(), location.getY(), location.getZ(), + coordinates.getX(), coordinates.getY()); } /** diff --git a/src/main/java/ru/erius/lab5/parser/Adapters.java b/src/main/java/ru/erius/lab5/parser/Adapters.java index 5747a73..3f4e455 100644 --- a/src/main/java/ru/erius/lab5/parser/Adapters.java +++ b/src/main/java/ru/erius/lab5/parser/Adapters.java @@ -1,15 +1,39 @@ package ru.erius.lab5.parser; +import ru.erius.lab5.data.Color; +import ru.erius.lab5.data.Coordinates; +import ru.erius.lab5.data.Country; +import ru.erius.lab5.data.Location; +import ru.erius.lab5.util.UtilFunctions; + import javax.xml.bind.annotation.adapters.XmlAdapter; import java.time.LocalDate; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Arrays; +import java.util.Locale; public final class Adapters { + public final static LocalDate DEFAULT_DATE = LocalDate.of(1970, 1, 1); + public final static int DEFAULT_HEIGHT = 150; + public final static Color DEFAULT_COLOR = Color.BLACK; + public final static Country DEFAULT_COUNTRY = Country.UNITED_KINGDOM; + public final static String DEFAULT_NAME = "name", + DEFAULT_PASSPORT = "passport"; + public final static int DEFAULT_COORDINATE = 0; + public final static Coordinates DEFAULT_COORDINATES = new Coordinates(DEFAULT_COORDINATE, DEFAULT_COORDINATE); + public final static Location DEFAULT_LOCATION = new Location(DEFAULT_COORDINATE, DEFAULT_COORDINATE, DEFAULT_COORDINATE, DEFAULT_NAME); + public static class LocalDateAdapter extends XmlAdapter { @Override public LocalDate unmarshal(String v) throws Exception { - return LocalDate.parse(v); + try { + return LocalDate.parse(v); + } catch (DateTimeParseException e) { + System.err.printf("Не удалось преобразовать %s в тип LocalDate, используем значение по умолчанию %s\n", v, DEFAULT_DATE); + return DEFAULT_DATE; + } } @Override @@ -21,8 +45,17 @@ public final class Adapters { public static class CoordinateYAdapter extends XmlAdapter { @Override public Float unmarshal(String v) throws Exception { - float result = Float.parseFloat(v); - return result > -816F ? result : 0F; + float result; + try { + result = Float.parseFloat(v); + } catch (NumberFormatException e) { + return (float) DEFAULT_COORDINATE; + } + if (result <= -816F) { + System.err.printf("Координата Y %s не может быть меньше или равна -816, используем значение по умолчанию %s\n", v, DEFAULT_COORDINATE); + return (float) DEFAULT_COORDINATE; + } + return result; } @Override @@ -36,9 +69,16 @@ public final class Adapters { public Integer unmarshal(String v) throws Exception { if (v == null) return null; - int result = Integer.parseInt(v); - if (result <= 0) - return 1; + int result; + try { + result = Integer.parseInt(v); + } catch (NumberFormatException e) { + return DEFAULT_HEIGHT; + } + if (result <= 0) { + System.err.printf("Рост %s не может быть меньше или равен 0, используем значение по умолчанию %s\n", v, DEFAULT_HEIGHT); + return DEFAULT_HEIGHT; + } return result; } @@ -51,7 +91,11 @@ public final class Adapters { public static class NameAdapter extends XmlAdapter { @Override public String unmarshal(String v) throws Exception { - return v.isEmpty() ? "none" : v; + if (v.isEmpty()) { + System.err.printf("Имя не может быть пустым, используем значение по умолчанию %s\n", DEFAULT_NAME); + return DEFAULT_NAME; + } + return v; } @Override @@ -63,7 +107,11 @@ public final class Adapters { public static class PassportAdapter extends XmlAdapter { @Override public String unmarshal(String v) throws Exception { - return v.length() < 8 ? "no_passport" : v; + if (v.length() < 8) { + System.err.printf("Номер паспорта %s должен быть как минимум 8 символов в длину, используем значение по умолчанию %s\n", v, DEFAULT_PASSPORT); + return DEFAULT_PASSPORT; + } + return v; } @Override @@ -71,4 +119,38 @@ public final class Adapters { return v; } } + + public static class ColorAdapter extends XmlAdapter { + @Override + public Color unmarshal(String v) throws Exception { + Color color = UtilFunctions.enumOrNull(v.toUpperCase(Locale.ROOT), Color.class); + if (color == null) { + System.err.printf("Цвет глаз %s не соответствует одному из этих вариантов - %s, используем значение по умолчанию %s\n", v, Arrays.toString(Color.values()), DEFAULT_COLOR); + return DEFAULT_COLOR; + } + return color; + } + + @Override + public String marshal(Color v) throws Exception { + return v.toString(); + } + } + + public static class CountryAdapter extends XmlAdapter { + @Override + public Country unmarshal(String v) throws Exception { + Country country = UtilFunctions.enumOrNull(v.toUpperCase(Locale.ROOT), Country.class); + if (country == null) { + System.err.printf("Национальность %s не соответствует одному из этих вариантов - %s, используем значение по умолчанию %s\n", v, Arrays.toString(Country.values()), DEFAULT_COUNTRY); + return DEFAULT_COUNTRY; + } + return country; + } + + @Override + public String marshal(Country v) throws Exception { + return v.toString(); + } + } }