more xml flexibility, minor fixes

This commit is contained in:
Egor 2022-03-22 02:19:39 +03:00
parent 4f8d6b45d0
commit 51caa000f3
9 changed files with 157 additions and 66 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 KiB

After

Width:  |  Height:  |  Size: 462 KiB

View file

@ -3,7 +3,7 @@ plugins {
} }
group = "ru.erius" group = "ru.erius"
version = "1.1" version = "1.2"
val mainClass = "$group.${name.toLowerCase()}.$name" val mainClass = "$group.${name.toLowerCase()}.$name"
repositories { repositories {

View file

@ -16,6 +16,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.stream.Collectors;
/** /**
* Класс базы данных людей, реализующий интерфейс Database * Класс базы данных людей, реализующий интерфейс Database
@ -34,8 +35,6 @@ public class PeopleDatabase implements Database {
private JAXBContext context; private JAXBContext context;
@XmlTransient @XmlTransient
private File file; private File file;
@XmlTransient
private String errorMessage;
@Getter @Getter
@XmlElement(name = "person") @XmlElement(name = "person")
private TreeSet<Person> collection = new TreeSet<>(); private TreeSet<Person> collection = new TreeSet<>();
@ -85,14 +84,10 @@ public class PeopleDatabase implements Database {
} }
if (file.isDirectory()) if (file.isDirectory())
file = createFile(file); file = createFile(file);
if (!file.canRead()) { if (!file.canRead())
errorMessage = String.format("У вас нет прав на чтение файла %s", file.getAbsolutePath()); throw new DatabaseLoadFailedException("У вас нет прав на чтение файла %s", file.getAbsolutePath());
throw new DatabaseLoadFailedException(errorMessage); if (!file.canWrite())
} throw new DatabaseLoadFailedException("У вас нет прав на запись в файл %s", file.getAbsolutePath());
if (!file.canWrite()) {
errorMessage = String.format("У вас нет прав на запись в файл %s", file.getAbsolutePath());
throw new DatabaseLoadFailedException(errorMessage);
}
this.file = file; this.file = file;
try { try {
@ -117,15 +112,13 @@ public class PeopleDatabase implements Database {
@Override @Override
public void save() throws Database.DatabaseSaveFailedException { public void save() throws Database.DatabaseSaveFailedException {
if (!file.exists()) { if (!file.exists()) {
System.out.println("Файла " + file.getAbsolutePath() + " не существует, "); System.out.println("Файла " + file.getAbsolutePath() + " не существует, возможно он был удален, пытаюсь воссоздать файл...");
boolean created;
try { try {
created = file.createNewFile(); file.createNewFile();
System.out.println("Файл был успешно создан");
} catch (IOException e) { } catch (IOException e) {
throw new DatabaseSaveFailedException("Не удается создать файл заново, пожалуйста, сделайте это вручную и попробуйте еще раз");
} }
errorMessage = "Файла %s не существует, возможно он был удален";
throw new DatabaseSaveFailedException(errorMessage, file.getAbsolutePath());
} }
try { try {
Marshaller marshaller = context.createMarshaller(); Marshaller marshaller = context.createMarshaller();
@ -154,9 +147,9 @@ public class PeopleDatabase implements Database {
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder("PeopleDatabase(\n"); String result = "PeopleDatabase(";
this.collection.forEach(p -> sb.append("\t").append(p).append("\n")); result += this.collection.stream().map(Person::toString).collect(Collectors.joining(", "));
sb.append(")"); result += ")";
return sb.toString(); return result;
} }
} }

View file

@ -6,7 +6,6 @@ import java.io.*;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors;
/** /**
* Класс обработчика командной строки, реализует шаблон проектирования Singleton, * Класс обработчика командной строки, реализует шаблон проектирования Singleton,

View file

@ -66,7 +66,8 @@ public final class PeopleDatabaseCommands {
} }
public static void show(PeopleDatabase peopleDatabase) { 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) { public static void add(PeopleDatabase peopleDatabase) {

View file

@ -10,7 +10,7 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/** /**
* Класс данных координат * Класс данных координат
*/ */
@Data @NoArgsConstructor @EqualsAndHashCode @ToString @Data @EqualsAndHashCode @ToString
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class Coordinates implements Comparable<Coordinates> { public class Coordinates implements Comparable<Coordinates> {
@ -24,13 +24,16 @@ public class Coordinates implements Comparable<Coordinates> {
@XmlJavaTypeAdapter(Adapters.CoordinateYAdapter.class) @XmlJavaTypeAdapter(Adapters.CoordinateYAdapter.class)
private Float y; private Float y;
private Coordinates() {
this.x = Adapters.DEFAULT_COORDINATE;
this.y = (float) Adapters.DEFAULT_COORDINATE;
}
/** /**
* Конструктор с параметрами * Конструктор с параметрами
* *
* @param x Координата X * @param x Координата X
* @param y Координата Y * @param y Координата Y
*
* @throws IllegalArgumentException Если Y меньше или равен -816
*/ */
public Coordinates(float x, float y) { public Coordinates(float x, float y) {
this.x = x; this.x = x;
@ -41,13 +44,11 @@ public class Coordinates implements Comparable<Coordinates> {
* Сеттер для поля y * Сеттер для поля y
* *
* @param y Координата Y * @param y Координата Y
*
* @throws IllegalArgumentException Если Y меньше или равен -816
*/ */
public void setY(float y) { public void setY(float y) {
this.y = y; this.y = y;
if (y <= -816) if (y <= -816)
this.y = 0F; this.y = (float) Adapters.DEFAULT_COORDINATE;
} }
private double distance() { private double distance() {

View file

@ -6,7 +6,6 @@ import ru.erius.lab5.parser.Adapters;
import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.util.Comparator; import java.util.Comparator;
/** /**
@ -16,7 +15,6 @@ import java.util.Comparator;
@Data @EqualsAndHashCode @ToString @Data @EqualsAndHashCode @ToString
@XmlAccessorType(XmlAccessType.FIELD) @XmlAccessorType(XmlAccessType.FIELD)
public class Location implements Comparable<Location> { public class Location implements Comparable<Location> {
/** /**
* Координата X типа double * Координата X типа double
*/ */
@ -26,18 +24,20 @@ public class Location implements Comparable<Location> {
*/ */
private float y; private float y;
/** /**
* Координата Z типа Long, не может быть null * Координата Z типа long, не может быть null
*/ */
private Long z; private long z;
/** /**
* Имя локации, может быть null * Имя локации, может быть null
*/ */
@XmlElement(nillable = true) @XmlElement(nillable = true)
@XmlJavaTypeAdapter(Adapters.NameAdapter.class)
private String name; private String name;
private Location() { 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<Location> {
* @param z Координата Z * @param z Координата Z
* @param name Имя локации * @param name Имя локации
* *
* @throws IllegalArgumentException будет брошено, если name является пустой строкой
*
* @throws NullPointerException будет брошено в случае, если Z является null * @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.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
@ -62,13 +60,11 @@ public class Location implements Comparable<Location> {
/** /**
* Сеттер для поля name * Сеттер для поля name
* @param name Имя локации * @param name Имя локации
*
* @throws IllegalArgumentException Если name является пустой строкой
*/ */
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
if (name != null && name.isEmpty()) if (name != null && name.isEmpty())
this.name = null; this.name = Adapters.DEFAULT_NAME;
} }
/** /**

View file

@ -60,10 +60,12 @@ public class Person implements Comparable<Person> {
/** /**
* Цвет глаз человека, не может быть null * Цвет глаз человека, не может быть null
*/ */
@XmlJavaTypeAdapter(Adapters.ColorAdapter.class)
private Color eyeColor; private Color eyeColor;
/** /**
* Национальность человека, не может быть null * Национальность человека, не может быть null
*/ */
@XmlJavaTypeAdapter(Adapters.CountryAdapter.class)
private Country nationality; private Country nationality;
/** /**
* Местоположение человека, может быть null * Местоположение человека, может быть null
@ -75,6 +77,14 @@ public class Person implements Comparable<Person> {
*/ */
private Person() { private Person() {
this.id = ++existingPeople; 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<Person> {
* @param nationality Национальность человека * @param nationality Национальность человека
* @param location Местоположение человека * @param location Местоположение человека
* *
* @throws IllegalArgumentException Если: * @throws NullPointerException Если name, coordinates, eyeColor или nationality являются null
* name является пустой строкой,
* height меньше 0,
* Длина passportID меньше 8 символов
*
* @throws NullPointerException Если 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) { @NonNull Color eyeColor, @NonNull Country nationality, Location location) {
this.id = ++existingPeople; this.id = ++existingPeople;
this.creationDate = LocalDate.now(); this.creationDate = LocalDate.now();
@ -129,40 +134,54 @@ public class Person implements Comparable<Person> {
* *
* @param name * @param name
* Имя человека * Имя человека
*
* @throws IllegalArgumentException
* Если имя является пустой строкой
*/ */
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
if (name.isEmpty()) if (name.isEmpty())
this.name = "none"; this.name = Adapters.DEFAULT_NAME;
} }
/** /**
* Сеттер для поля height * Сеттер для поля height
* *
* @param height Рост человека * @param height Рост человека
*
* @throws IllegalArgumentException Если рост меньше 0
*/ */
public void setHeight(Integer height) { public void setHeight(Integer height) {
this.height = height; this.height = height;
if (height != null && height <= 0) if (height != null && height <= 0)
this.height = 150; this.height = Adapters.DEFAULT_HEIGHT;
} }
/** /**
* Сеттер для поля passportID * Сеттер для поля passportID
* *
* @param passportID Номер паспорта человека * @param passportID Номер паспорта человека
*
* @throws IllegalArgumentException Если номер паспорта меньше 8 символов в длину
*/ */
public void setPassportID(String passportID) { public void setPassportID(String passportID) {
this.passportID = passportID; this.passportID = passportID;
if (passportID != null && passportID.length() < 8) 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" +
"\ата создания: %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());
} }
/** /**

View file

@ -1,15 +1,39 @@
package ru.erius.lab5.parser; 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 javax.xml.bind.annotation.adapters.XmlAdapter;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.Locale;
public final class Adapters { 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<String, LocalDate> { public static class LocalDateAdapter extends XmlAdapter<String, LocalDate> {
@Override @Override
public LocalDate unmarshal(String v) throws Exception { public LocalDate unmarshal(String v) throws Exception {
try {
return LocalDate.parse(v); return LocalDate.parse(v);
} catch (DateTimeParseException e) {
System.err.printf("Не удалось преобразовать %s в тип LocalDate, используем значение по умолчанию %s\n", v, DEFAULT_DATE);
return DEFAULT_DATE;
}
} }
@Override @Override
@ -21,8 +45,17 @@ public final class Adapters {
public static class CoordinateYAdapter extends XmlAdapter<String, Float> { public static class CoordinateYAdapter extends XmlAdapter<String, Float> {
@Override @Override
public Float unmarshal(String v) throws Exception { public Float unmarshal(String v) throws Exception {
float result = Float.parseFloat(v); float result;
return result > -816F ? result : 0F; 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 @Override
@ -36,9 +69,16 @@ public final class Adapters {
public Integer unmarshal(String v) throws Exception { public Integer unmarshal(String v) throws Exception {
if (v == null) if (v == null)
return null; return null;
int result = Integer.parseInt(v); int result;
if (result <= 0) try {
return 1; 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; return result;
} }
@ -51,7 +91,11 @@ public final class Adapters {
public static class NameAdapter extends XmlAdapter<String, String> { public static class NameAdapter extends XmlAdapter<String, String> {
@Override @Override
public String unmarshal(String v) throws Exception { 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 @Override
@ -63,7 +107,11 @@ public final class Adapters {
public static class PassportAdapter extends XmlAdapter<String, String> { public static class PassportAdapter extends XmlAdapter<String, String> {
@Override @Override
public String unmarshal(String v) throws Exception { 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 @Override
@ -71,4 +119,38 @@ public final class Adapters {
return v; return v;
} }
} }
public static class ColorAdapter extends XmlAdapter<String, Color> {
@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<String, Country> {
@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();
}
}
} }