Skip to content
Merged
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
17 changes: 17 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
<encoding>UTF-8</encoding>
<project.build.sourceEncoding>${encoding}</project.build.sourceEncoding>
<project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding>
<mapstruct.version>1.6.3</mapstruct.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
<excludedGroups>integration</excludedGroups>
</properties>

Expand Down Expand Up @@ -95,6 +97,11 @@
<version>1.18.48</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>com.dlsc.formsfx</groupId>
<artifactId>formsfx-core</artifactId>
Expand Down Expand Up @@ -165,6 +172,16 @@
<artifactId>lombok</artifactId>
<version>1.18.48</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok-mapstruct-binding.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-proc:full</arg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import com.DesktopApplicationClientJava.Api.Dto.response.ResourceDto;
import com.DesktopApplicationClientJava.Api.Dto.response.UserDto;
import com.DesktopApplicationClientJava.session.Session;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -50,9 +49,6 @@ public ApiClient(Session session) {
.build();
this.objectMapper = new ObjectMapper();
this.objectMapper.registerModule(new JavaTimeModule());
// FIXME: temporary — backend returns firstname/lastname instead of firstName/lastName.
// Remove once backend uses camelCase; then unknown properties should fail fast again.
this.objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}

// ======================== AUTH ========================
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public record UserDto(
UUID uuid,
String email,
Role role,
String firstName,
String lastName,
String firstname,
String lastname,
Boolean enabled,
LocalDateTime createdAt,
LocalDateTime updatedAt) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.DesktopApplicationClientJava.mapper;

import com.DesktopApplicationClientJava.Api.Dto.response.FileDto;
import com.DesktopApplicationClientJava.entities.FileInfo;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface FileMapper {

FileMapper INSTANCE = Mappers.getMapper(FileMapper.class);

FileInfo toEntity(FileDto dto);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.DesktopApplicationClientJava.mapper;

import com.DesktopApplicationClientJava.Api.Dto.response.ResourceDto;
import com.DesktopApplicationClientJava.entities.Resource;
import org.mapstruct.Mapper;
import org.mapstruct.NullValueMappingStrategy;
import org.mapstruct.factory.Mappers;

@Mapper(
uses = FileMapper.class,
// Бэкенд присылает null вместо пустого списка файлов.
nullValueIterableMappingStrategy = NullValueMappingStrategy.RETURN_DEFAULT)
public interface ResourceMapper {

ResourceMapper INSTANCE = Mappers.getMapper(ResourceMapper.class);

Resource toEntity(ResourceDto dto);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.DesktopApplicationClientJava.mapper;

import com.DesktopApplicationClientJava.Api.Dto.response.UserDto;
import com.DesktopApplicationClientJava.entities.User;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface UserMapper {

UserMapper INSTANCE = Mappers.getMapper(UserMapper.class);

// Имена в контракте бэкенда в нижнем регистре, в сущности — camelCase.
@Mapping(target = "firstName", source = "firstname")
@Mapping(target = "lastName", source = "lastname")
User toEntity(UserDto dto);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import com.DesktopApplicationClientJava.Api.ApiClient;
import com.DesktopApplicationClientJava.Api.ApiException;
import com.DesktopApplicationClientJava.Api.Dto.request.Auth.LoginRequest;
import com.DesktopApplicationClientJava.Api.Dto.response.UserDto;
import com.DesktopApplicationClientJava.entities.Role;
import com.DesktopApplicationClientJava.entities.User;
import com.DesktopApplicationClientJava.mapper.UserMapper;
import com.DesktopApplicationClientJava.services.AuthService;
import com.DesktopApplicationClientJava.services.ServiceException;
import com.DesktopApplicationClientJava.session.Session;
Expand All @@ -25,8 +25,7 @@ public AuthServiceImpl(ApiClient apiClient, Session session) {
public User login(String email, String password) {
try {
apiClient.login(new LoginRequest(email, password));
UserDto me = apiClient.getMe();
User user = toEntity(me);
User user = UserMapper.INSTANCE.toEntity(apiClient.getMe());
session.setCurrentUser(user);
return user;
} catch (ApiException e) {
Expand Down Expand Up @@ -70,11 +69,6 @@ public boolean isModerator() {
return hasRole(Role.MODER);
}

private User toEntity(UserDto dto) {
return new User(
dto.uuid(), dto.email(), dto.role(), dto.firstName(), dto.lastName(), dto.enabled());
}

private static int level(Role role) {
return switch (role) {
case USER -> 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import com.DesktopApplicationClientJava.Api.ApiClient;
import com.DesktopApplicationClientJava.Api.ApiException;
import com.DesktopApplicationClientJava.Api.Dto.response.FileDto;
import com.DesktopApplicationClientJava.entities.FileInfo;
import com.DesktopApplicationClientJava.mapper.FileMapper;
import com.DesktopApplicationClientJava.services.FileService;
import com.DesktopApplicationClientJava.services.ServiceException;
import java.io.IOException;
Expand All @@ -20,8 +20,7 @@ public FileServiceImpl(ApiClient apiClient) {

public FileInfo uploadFile(UUID resourceId, Path file) {
try {
FileDto dto = apiClient.uploadFile(resourceId, file);
return new FileInfo(dto.uuid(), dto.name(), dto.contentType(), dto.size());
return FileMapper.INSTANCE.toEntity(apiClient.uploadFile(resourceId, file));
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
} catch (IOException | InterruptedException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import com.DesktopApplicationClientJava.Api.Dto.request.Resource.CreateResourceRequest;
import com.DesktopApplicationClientJava.Api.Dto.request.Resource.ResourceFilterRequest;
import com.DesktopApplicationClientJava.Api.Dto.request.Resource.UpdateResourceRequest;
import com.DesktopApplicationClientJava.Api.Dto.response.ResourceDto;
import com.DesktopApplicationClientJava.entities.FileInfo;
import com.DesktopApplicationClientJava.entities.Resource;
import com.DesktopApplicationClientJava.mapper.ResourceMapper;
import com.DesktopApplicationClientJava.services.ResourceService;
import com.DesktopApplicationClientJava.services.ServiceException;
import com.DesktopApplicationClientJava.services.filter.ResourceFilter;
Expand All @@ -29,7 +28,7 @@ public List<Resource> search(ResourceFilter filter, long offset, long count) {
new ResourceFilterRequest(filter.getTitle(), filter.getDescription(), null, null);
try {
return apiClient.findResourcesByFilters(req, offset, count, "createdAt", "desc").stream()
.map(this::toEntity)
.map(ResourceMapper.INSTANCE::toEntity)
.toList();
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
Expand All @@ -41,7 +40,8 @@ public List<Resource> search(ResourceFilter filter, long offset, long count) {
@Override
public Resource create(String title, String description) {
try {
return toEntity(apiClient.createResource(new CreateResourceRequest(title, description)));
return ResourceMapper.INSTANCE.toEntity(
apiClient.createResource(new CreateResourceRequest(title, description)));
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
} catch (IOException | InterruptedException e) {
Expand All @@ -52,7 +52,7 @@ public Resource create(String title, String description) {
@Override
public Resource getById(UUID resourceId) {
try {
return toEntity(apiClient.findResourceById(resourceId));
return ResourceMapper.INSTANCE.toEntity(apiClient.findResourceById(resourceId));
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
} catch (IOException | InterruptedException e) {
Expand All @@ -67,7 +67,7 @@ public List<Resource> search(
new ResourceFilterRequest(filter.getTitle(), filter.getDescription(), null, null);
try {
return apiClient.findResourcesByFilters(req, offset, count, sortBy, sortDir).stream()
.map(this::toEntity)
.map(ResourceMapper.INSTANCE::toEntity)
.toList();
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
Expand All @@ -80,7 +80,7 @@ public List<Resource> search(
public Resource update(UUID resourceId, String title, String description) {
UpdateResourceRequest req = new UpdateResourceRequest(title, description);
try {
return toEntity(apiClient.updateResource(resourceId, req));
return ResourceMapper.INSTANCE.toEntity(apiClient.updateResource(resourceId, req));
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
} catch (IOException | InterruptedException e) {
Expand All @@ -98,15 +98,4 @@ public void delete(UUID resourceId) {
throw new ServiceException("Ошибка соединения с сервером");
}
}

private Resource toEntity(ResourceDto dto) {
List<FileInfo> files =
dto.files() == null
? List.of()
: dto.files().stream()
.map(f -> new FileInfo(f.uuid(), f.name(), f.contentType(), f.size()))
.toList();
return new Resource(
dto.uuid(), dto.title(), dto.description(), dto.createdAt(), dto.updatedAt(), files);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import com.DesktopApplicationClientJava.Api.Dto.request.Admin.RegisterRequest;
import com.DesktopApplicationClientJava.Api.Dto.request.Admin.UpdateUserRequest;
import com.DesktopApplicationClientJava.Api.Dto.request.Admin.UserFilterRequest;
import com.DesktopApplicationClientJava.Api.Dto.response.UserDto;
import com.DesktopApplicationClientJava.entities.User;
import com.DesktopApplicationClientJava.mapper.UserMapper;
import com.DesktopApplicationClientJava.services.ServiceException;
import com.DesktopApplicationClientJava.services.UsersService;
import com.DesktopApplicationClientJava.services.data.RegisterData;
Expand Down Expand Up @@ -37,7 +37,7 @@ public List<User> search(UserFilter filter, long offset, long count) {

try {
return apiClient.getUsersByFilters(req, offset, count, "createdAt", "desc").stream()
.map(this::toEntity)
.map(UserMapper.INSTANCE::toEntity)
.toList();
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
Expand All @@ -49,7 +49,7 @@ public List<User> search(UserFilter filter, long offset, long count) {
@Override
public User getById(UUID uuid) {
try {
return toEntity(apiClient.getUserById(uuid));
return UserMapper.INSTANCE.toEntity(apiClient.getUserById(uuid));
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
} catch (IOException | InterruptedException e) {
Expand All @@ -67,7 +67,7 @@ public User create(RegisterData data) {
data.getFirstName(),
data.getLastName());
try {
return toEntity(apiClient.createUser(req));
return UserMapper.INSTANCE.toEntity(apiClient.createUser(req));
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
} catch (IOException | InterruptedException e) {
Expand All @@ -86,7 +86,7 @@ public User update(UUID uuid, UpdateUserData data) {
data.getLastName());

try {
return toEntity(apiClient.updateUser(uuid, req));
return UserMapper.INSTANCE.toEntity(apiClient.updateUser(uuid, req));
} catch (ApiException e) {
throw new ServiceException(e.getMessage(), e.getStatus());
} catch (IOException | InterruptedException e) {
Expand All @@ -104,9 +104,4 @@ public void delete(UUID uuid) {
throw new ServiceException("Ошибка соединения с сервером");
}
}

private User toEntity(UserDto dto) {
return new User(
dto.uuid(), dto.email(), dto.role(), dto.firstName(), dto.lastName(), dto.enabled());
}
}
25 changes: 25 additions & 0 deletions src/test/java/mapper/FileMapperTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mapper;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.DesktopApplicationClientJava.Api.Dto.response.FileDto;
import com.DesktopApplicationClientJava.entities.FileInfo;
import com.DesktopApplicationClientJava.mapper.FileMapper;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class FileMapperTest {

@Test
void mapsAllFields() {
UUID uuid = UUID.randomUUID();
FileDto dto = new FileDto(uuid, "отчёт.pdf", "application/pdf", 12345L);

FileInfo file = FileMapper.INSTANCE.toEntity(dto);

assertEquals(uuid, file.getUuid());
assertEquals("отчёт.pdf", file.getName());
assertEquals("application/pdf", file.getContentType());
assertEquals(12345L, file.getSize());
}
}
54 changes: 54 additions & 0 deletions src/test/java/mapper/ResourceMapperTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package mapper;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.DesktopApplicationClientJava.Api.Dto.response.FileDto;
import com.DesktopApplicationClientJava.Api.Dto.response.ResourceDto;
import com.DesktopApplicationClientJava.entities.Resource;
import com.DesktopApplicationClientJava.mapper.ResourceMapper;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.Test;

class ResourceMapperTest {

@Test
void mapsAllFieldsIncludingFiles() {
UUID uuid = UUID.randomUUID();
UUID fileUuid = UUID.randomUUID();
ResourceDto dto =
new ResourceDto(
uuid,
"Отчёт",
"Описание",
LocalDateTime.parse("2026-01-02T03:04:05"),
LocalDateTime.parse("2026-01-03T04:05:06"),
List.of(new FileDto(fileUuid, "отчёт.pdf", "application/pdf", 12345L)));

Resource resource = ResourceMapper.INSTANCE.toEntity(dto);

assertEquals(uuid, resource.getUuid());
assertEquals("Отчёт", resource.getTitle());
assertEquals("Описание", resource.getDescription());
assertEquals(LocalDateTime.parse("2026-01-02T03:04:05"), resource.getCreatedAt());
assertEquals(LocalDateTime.parse("2026-01-03T04:05:06"), resource.getUpdatedAt());
assertEquals(1, resource.getFiles().size());
assertEquals(fileUuid, resource.getFiles().get(0).getUuid());
assertEquals("отчёт.pdf", resource.getFiles().get(0).getName());
assertEquals("application/pdf", resource.getFiles().get(0).getContentType());
assertEquals(12345L, resource.getFiles().get(0).getSize());
}

@Test
void nullFilesBecomeEmptyList() {
ResourceDto dto =
new ResourceDto(
UUID.randomUUID(), "Отчёт", "Описание", LocalDateTime.now(), LocalDateTime.now(), null);

Resource resource = ResourceMapper.INSTANCE.toEntity(dto);

assertTrue(resource.getFiles().isEmpty());
}
}
Loading
Loading