Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ target/
!**/src/test/**/target/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
.idea
.run
*.iws
*.iml
*.ipr
Expand Down Expand Up @@ -35,4 +33,6 @@ build/
.vscode/

### Mac OS ###
.DS_Store
.DS_Store

output
34 changes: 17 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# Практическое задание 1 # CSV Writer
## Prerequisites
- JDK 17+
- Apache Maven 3.9+

Мы пишем приложение, которое должно генерировать отчеты в разных форматах и нам хочется генерировать какой-нибудь отчёт в CSV, но проблема в том, что у нас нет такого инструмента. Поэтому мы решаем, что нам нужна библиотека для генерации CSV файлов.
Реализация может быть построена с помощью Reflection и аннотаций.
## Getting started
```bash
git clone https://github.com/swankygawk/CsvWriter.git
cd CsvWriter
```

Папка model содержит классы, которые нужно сохранять в CSV. Классы можно изменять и добавлять новые.
## Launching demo
```bash
mvn compile exec:java -Dexec.mainClass="org.writer.Application"
```
Generated CSV files will be located in the `output` directory

**Описание:**<br>
✅ Написать реализацию Writable, которая будет сохранять объекты в CSV формате в файл<br>
✅ Написать unit тесты<br>
✅ Написать JavaDoc<br>
✅ Для генерации тестовых данных можно использовать Datafaker<br>
✅ В main должно быть несколько примеров сохранения данных в файл

**Как выполнить:**
1. Сделать форк этого проекта
2. Сделать ветку dev в своем проекте. Выполнять работу в ней
3. После выполнения работы открыть Pull Request в master
4. Назначить ментора ревьювером
5. Отправить ссылку на PR в тг чат ментору
## Launching tests
```bash
mvn test
```
20 changes: 20 additions & 0 deletions TASKREADME.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Практическое задание 1 # CSV Writer

Мы пишем приложение, которое должно генерировать отчеты в разных форматах и нам хочется генерировать какой-нибудь отчёт в CSV, но проблема в том, что у нас нет такого инструмента. Поэтому мы решаем, что нам нужна библиотека для генерации CSV файлов.
Реализация может быть построена с помощью Reflection и аннотаций.

Папка model содержит классы, которые нужно сохранять в CSV. Классы можно изменять и добавлять новые.

**Описание:**<br>
✅ Написать реализацию Writable, которая будет сохранять объекты в CSV формате в файл<br>
✅ Написать unit тесты<br>
✅ Написать JavaDoc<br>
✅ Для генерации тестовых данных можно использовать Datafaker<br>
✅ В main должно быть несколько примеров сохранения данных в файл

**Как выполнить:**
1. Сделать форк этого проекта
2. Сделать ветку dev в своем проекте. Выполнять работу в ней
3. После выполнения работы открыть Pull Request в master
4. Назначить ментора ревьювером
5. Отправить ссылку на PR в тг чат ментору
13 changes: 13 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,31 @@
</properties>

<dependencies>
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>2.5.1</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>

</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.27.6</version>
<scope>test</scope>
</dependency>
</dependencies>

</project>
72 changes: 72 additions & 0 deletions src/main/java/org/writer/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.writer;

import org.writer.model.Person;
import org.writer.model.Student;
import org.writer.util.TestDataGenerator;
import org.writer.writer.CsvWriterImpl;
import org.writer.writer.Writable;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

public final class Application {
private static final String OUTPUT_DIR = "output";

public static void main(String[] args) {
System.out.println();

createOutputDir();

Writable csvWriter = new CsvWriterImpl();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");

// Person
String personsTimestamp = LocalDateTime.now().format(formatter);
String personsFileName = OUTPUT_DIR + "/persons-" + personsTimestamp + ".csv";
int personsCount = TestDataGenerator.generateRandomInt(2, 100);

System.out.println("Генерация случайных Person...");
List<Person> persons = TestDataGenerator.generatePersons(personsCount);

System.out.println("Запись " + personsCount + " объектов Person в файл " + personsFileName + "...");
csvWriter.writeToFile(persons, personsFileName);
System.out.println("Файл "+ personsFileName + " успешно создан");
System.out.println("---------------------------------------------");

// Student
String studentsTimestamp = LocalDateTime.now().format(formatter);
String studentsFileName = OUTPUT_DIR + "/students-" + studentsTimestamp + ".csv";
int studentsCount = TestDataGenerator.generateRandomInt(2, 100);

System.out.println("Генерация случайных Student...");
List<Student> students = TestDataGenerator.generateStudents(studentsCount);

System.out.println("Запись " + studentsCount + " объектов Student в файл " + studentsFileName + "...");
csvWriter.writeToFile(students, studentsFileName);
System.out.println("Файл "+ studentsFileName + " успешно создан");

System.out.println();
}

/**
* Создаёт директорию для вывода, если она ещё не существует.
*
* @throws RuntimeException если не удалось создать директорию.
*/
private static void createOutputDir() {
Path outputPath = Path.of(OUTPUT_DIR);
if (!Files.exists(outputPath)) {
try {
Files.createDirectories(outputPath);
System.out.println("Создана директория для вывода: " + OUTPUT_DIR);
System.out.println();
} catch (IOException e) {
throw new RuntimeException("Не удалось создать директорию для вывода: " + OUTPUT_DIR, e);
}
}
}
}
7 changes: 0 additions & 7 deletions src/main/java/org/writer/Main.java

This file was deleted.

9 changes: 0 additions & 9 deletions src/main/java/org/writer/Writable.java

This file was deleted.

30 changes: 30 additions & 0 deletions src/main/java/org/writer/annotation/CsvColumn.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.writer.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Помечает поле класса для включения в CSV-файл.
*
* @see CsvEntity
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CsvColumn {
/**
* Название столбца в заголовке CSV-файла.
*
* @return название столбца
*/
String name();

/**
* Порядок столбца в CSV-файле (слева направо), начиная с 1.
* Чем меньше число, тем левее столбец.
*
* @return порядковый номер столбца
*/
int order();
}
16 changes: 16 additions & 0 deletions src/main/java/org/writer/annotation/CsvEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.writer.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Помечает класс, экземпляры которого можно экспортировать в CSV.
*
* @see CsvColumn
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CsvEntity {
}
10 changes: 8 additions & 2 deletions src/main/java/org/writer/model/Person.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.writer.annotation.CsvColumn;
import org.writer.annotation.CsvEntity;

@Data
@Builder
@AllArgsConstructor
@CsvEntity
public class Person {

@CsvColumn(name = "firstName", order = 1)
private String firstName;

@CsvColumn(name = "lastName", order = 2)
private String lastName;

@CsvColumn(name = "birthDay", order = 5)
private int dayOfBirth;

@CsvColumn(name = "birthMonth", order = 4)
private Months monthOfBirth;

@CsvColumn(name = "birthYear", order = 3)
private int yearOfBirth;

}
6 changes: 5 additions & 1 deletion src/main/java/org/writer/model/Student.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import org.writer.annotation.CsvColumn;
import org.writer.annotation.CsvEntity;

import java.util.List;

@Data
@Builder
@AllArgsConstructor
@CsvEntity
public class Student {

@CsvColumn(name = "name", order = 1)
private String name;

@CsvColumn(name = "score", order = 2)
private List<String> score;
}
89 changes: 89 additions & 0 deletions src/main/java/org/writer/util/TestDataGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.writer.util;

import net.datafaker.Faker;
import org.writer.model.Months;
import org.writer.model.Person;
import org.writer.model.Student;

import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
* Вспомогательный класс для генерации тестовых данных
*/
public final class TestDataGenerator {
private static final Faker FAKER = new Faker();

private TestDataGenerator() {}

/**
* Генерирует случайное int в пределах границ (включительно).
*
* @param min нижняя граница.
* @param max верхняя граница.
*
* @return случайное int.
*/
public static int generateRandomInt(final int min, final int max) {
return FAKER.number().numberBetween(min, max + 1);
}

/**
* Генерирует список случайных объектов {@link Person}.
*
* @param count желаемое количество объектов.
*
* @return список сгенерированных объектов {@code Person}.
*/
public static List<Person> generatePersons(final int count) {
return IntStream.range(0, count)
.mapToObj(i -> Person.builder()
.firstName(FAKER.name().firstName())
.lastName(FAKER.name().lastName())
.dayOfBirth(FAKER.number().numberBetween(1, 28))
.monthOfBirth(getRandomMonth())
.yearOfBirth(FAKER.number().numberBetween(1925, 2025))
.build())
.toList();
}

/**
* Генерирует список случайных объектов {@link Student}.
*
* @param count желаемое количество объектов.
*
* @return список сгенерированных объектов {@code Student}.
*/
public static List<Student> generateStudents(final int count) {
return IntStream.range(0, count)
.mapToObj(i -> Student.builder()
.name(FAKER.name().fullName())
.score(generateRandomScores(FAKER.number().numberBetween(2, 9)))
.build())
.toList();
}

/**
* Вспомогательный метод для получения случайного месяца из enum {@link Months}.
*
* @return случайный месяц.
*/
private static Months getRandomMonth() {
Months[] months = Months.values();
return months[FAKER.number().numberBetween(0, months.length - 1)];
}

/**
* Вспомогательный метод для генерации списка случайных оценок.
*
* @param count количество оценок.
*
* @return список оценок в виде строк.
*/
private static List<String> generateRandomScores(final int count) {
return Stream.generate(() -> String.valueOf(FAKER.number().numberBetween(1, 6)))
.limit(count)
.toList();
}
}
Loading