본문 바로가기

자바 심화/TIL

프로젝트 문제 해결(역직렬화, git 에러)

개요

프로젝트를 진행하며 발생했던 문제 중 해결하는 데 어려움을 겪었던 사항들에 대해 기록하고 추후 같은 문제가 발생했을 경우 정리한 글을 바탕으로 좀 더 빠르게 해결할 수 있도록 할 것이다.

 

Json 직렬화, 역직렬화 문제

1. Cache 설정

2024-12-11T14:07:10.569+09:00 ERROR 25596 --- [hub] [io-19094-exec-2] [67591dfe8cd348ded9a885facc780af9-d9a885facc780af9] c.s.m.h.p.e.GlobalExceptionHandler       : Cannot serialize
2024-12-11T14:07:10.606+09:00 ERROR 25596 --- [hub] [io-19094-exec-2] [                                                 ] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.springframework.data.redis.serializer.SerializationException: Cannot serialize] with root cause
  • 프로젝트에서 Hub에 대한 값이 변경이 적기 때문에 Caching을 하기 위해 Redis에 Cache 데이터를 저장하려고 했을 때 발생한 에러 메시지이다.
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisCacheConfiguration configuration = RedisCacheConfiguration
                .defaultCacheConfig()
                // null을 캐싱하는지
                .disableCachingNullValues()
                // 기본 캐시 유지 시간 (Time to Live)
                .entryTtl(Duration.ofSeconds(60))
                // 캐시를 구분하는 접두사 설정
                .computePrefixWith(CacheKeyPrefix.simple())
                // 캐시에 저장할 값을 어떻게 직렬화 / 역직렬화 할 것인지
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));

        return RedisCacheManager
                .builder(connectionFactory)
                .cacheDefaults(configuration)
                .build();
    }
}
  • 기존 캐시 설정에서 serializeValuesWith 부분에서 RedisSerializer를 캐시를 실습했을 때 처럼 .java()로 사용했는데 보통 Redis와 상호작용을 위해 JSON 직렬화를 사용해야 해서 .json()으로 변경했다.

 

2. 요청 값에 대한 서버의 반환 타입 불일치

Hibernate: insert into p_hub (address,hubuuid,is_deleted,latitude,longitude,manager_id,name) values (?,?,?,?,?,?,?)
2024-12-11T14:15:13.957+09:00  WARN 11484 --- [hub] [io-19094-exec-2] [67591fe16574a9fe6a448fc034c4a23d-6a448fc034c4a23d] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: No acceptable representation]

// 요청에 대한 반환 값
{
    "timestamp": "2024-12-11T05:15:13.974+00:00",
    "status": 406,
    "error": "Not Acceptable",
    "path": "/hubs"
}
  • 캐시 파일 설정 이후 서버로 요청을 보내자 다음 에러와 함께 에러 값이 반환 되었다.

문제 해결을 위해 코드를 검토한 결과 JSON 직렬화/역직렬화 관련 문제인 것으로 확인 되었다.

@Entity
@Getter
@Table(name = "p_hub")
@AllArgsConstructor
@NoArgsConstructor
@Builder(access = AccessLevel.PRIVATE)
public class Hub extends BaseEntity implements Serializable {
// Entity Code 생략
}
  • 캐시와 연관되서 직렬화/역직렬화가 필요한 것이라고 판단되어 DTO와 Entity에 Serializable을 추가했다.
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder(access = AccessLevel.PRIVATE)
@ToString
public class HubResponse implements Serializable {
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    private UUID hubUUID;

    private String hubName;
    private String hubAddress;
    private Double hubLatitude;
    private Double hubLongitude;
    private String hubManagerId;

    public static HubResponse fromHub(Hub hub) {
        return HubResponse.builder()
                .hubUUID(hub.getHubUUID())
                .hubName(hub.getName())
                .hubAddress(hub.getAddress())
                .hubLatitude(hub.getLatitude())
                .hubLongitude(hub.getLongitude())
                .hubManagerId(hub.getManagerId())
                .build();
    }
}
  • 추가적으로 JSON이 UUID 타입을 직접적으로 지원하지 않는다고 해 UUID를 String으로 직렬화 하기 위해 @JsonFormat(shape = JsonFormat.Shape.STRING)을 추가했다.

 

3. PageableDefault 값 설정 문제

2024-12-11T15:21:42.652+09:00 ERROR 48800 --- [hub] [io-19094-exec-7] [67592f76b30a018bfc514cab91d8349e-fc514cab91d8349e] c.s.m.h.p.e.GlobalExceptionHandler       : No property 'created' found for type 'Hub'

@GetMapping
    public CommonResponse<GetHubsResponse> findAllHubs(
            @QuerydslPredicate(root = Hub.class) Predicate predicate,
            @PageableDefault(sort = "created_at") Pageable pageable
    ) {

        return CommonResponse.ofSuccess(hubQueryService.findAllHubs(predicate, pageable));
    }
  • Hub Entity가 BaseEntity를 상속받지 않은 상태에서 sort 값을 지정해서 'created_at'을 찾을 수 없다는 에러였다.
  • BaseEntity를 연결하지 않은 상태에서 테스트를 진행하기 위해 pageable default 값을 제거했다.

 

4. PagedModel이 역직렬화를 하지 못하는 문제

해당 문제는 혼자서 해결하지 못 하고 튜터님을 찾아가서 도움을 받았다.

2024-12-11T15:38:30.373+09:00 ERROR 55956 --- [hub] [io-19094-exec-9] [67593366ba4b3be60fe4b36c212394bb-0fe4b36c212394bb] c.s.m.h.p.e.GlobalExceptionHandler       : Could not read JSON:Cannot construct instance of com.sparta.msa.hub.application.dto.GetHubsResponse$HubPage (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: REDACTED (StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION disabled); line: 1, column: 145] (through reference chain: com.sparta.msa.hub.application.dto.GetHubsResponse["hubPage"])

 

기존 코드

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class GetHubsResponse implements Serializable {

    private HubPage hubPage;

    public static GetHubsResponse of(Page<Hub> hubPage) {
        return GetHubsResponse.builder()
                .hubPage(new HubPage(hubPage))
                .build();
    }

    @Getter
    @ToString
    public static class HubPage extends PagedModel<HubPage.Hub> {

        public HubPage(Page<com.sparta.msa.hub.domain.entity.Hub> hubPage) {
            super(
                    new PageImpl<>(
                            Hub.from(hubPage.getContent()),
                            hubPage.getPageable(),
                            hubPage.getTotalElements()
                    )
            );
        }

        @Getter
        @Builder
        @AllArgsConstructor
        public static class Hub {
            @JsonFormat(shape = JsonFormat.Shape.STRING)
            private UUID hubUUID;

            private String hubName;
            private String hubAddress;
            private Double latitude;
            private Double longitude;
            private Long managerId;

            public static List<Hub> from(List<com.sparta.msa.hub.domain.entity.Hub> hubList) {
                return hubList.stream()
                        .map(HubPage.Hub::from)
                        .toList();
            }

            public static Hub from(com.sparta.msa.hub.domain.entity.Hub hub) {
                return Hub.builder()
                        .hubUUID(hub.getHubUUID())
                        .hubName(hub.getName())
                        .hubAddress(hub.getAddress())
                        .latitude(hub.getLatitude())
                        .longitude(hub.getLongitude())
                        .managerId(hub.getManagerId())
                        .build();
            }
        }
    }
}
  • QueryDSL 실습에 사용했던 코드를 수정해서 사용했던 코드로 튜터님과 함께 문제 원인을 찾아본 결과 HubPage가 PagedModel을 상속받는데 여기서 직렬화 관련 문제가 발생했던 것이었다.

코드 수정

public static class HubPage implements Serializable{
    private List<Hub> content;
    private int pageNumber;
    private int pageSize;
    private long totalElements;

    public static HubPage from(Page<com.sparta.msa.hub.domain.entity.Hub> hubPage) {
        return
                new  HubPage(
                        HubPage.Hub.from(hubPage.getContent()),
                        hubPage.getPageable().getPageNumber(),
                        hubPage.getPageable().getPageSize(),
                        hubPage.getTotalElements()
                );
    }
  • PagedModel을 별도로 구성해서 사용하는 것으로 직렬화 문제를 해결했다.
  • 추후 PagedModel을 사용할 수 있도록 더 알아보고 싶다.

 

깃 내역 꼬임 문제

1. 문제 발생

Hub CRUD에 대한 기본 개발이 끝난 후 원격 레포지토리의 git 내역을 pull 받는 과정에서 hub 폴더를 루트 폴더로 인식해 hub 폴더 안에 gateway, server, order 등 다른 애플리케이션 폴더가 위치하는 문제가 발생했다.

 

이를 터미널에서 해결하려는 과정에서 git 내역이 꼬이는 문제가 발생했고, branch를 push해도 hub 자체의 코드를 추적하지 못하고 빈 폴더만 원격 브랜치에 올라가는 문제가 발생했다.

 

구글링 및 ChatGPT로도 원하는 내용을 찾지 못해 튜터님의 도움을 받아 해결했다.

 

2. 문제 해결

튜터님이 따로 실험하신 결과 꼬인 깃을 그 프로젝트에서 해결하는 것은 어렵다고 판단하셔서 새로 git clone을 받은 후 기존의 hub 폴더를 복사해 온 후 .git 파일과 불필요 파일을 제거한 후 git 내역을 새로 등록한 후 push 하는 것으로 해결했다.

 

원인은 hub를 .git파일이 있어서 root 폴더로 인식해서 git pull 시 허브 폴더 내로 다른 msa 폴더들이 위치하게 되는 것이었다.

 

열심히 작업하던 git 내역이 다 날아간 것은 아쉬운 일이었지만 다행히 작업했던 코드들은 멀쩡했고, 덕분에 .git 파일의 존재와 왜 허브 폴더를 루트 폴더로 인식했는지를 알게되었다.

 

정리

  • 멀쩡하게 동작하던 코드가 UUID와 Cahce로 인해 직렬화/역직렬화 문제가 발생했고, 해결하는데 많은 어려움을 겪었다. 좀 더 공부가 필요할 것 같다.
  • git도 모놀리식 구조에서는 겪지 않았던 문제를 겪었고, 해결하는 과정에서 많은 것을 배웠다.
  • 프로젝트를 하면서 일어났던 문제가 다음에는 발생하지 않도록 좀 더 주의하고 발생하더라도 이 정리글을 통해 빠른 해결을 할 수 있도록 해야겠다.

'자바 심화 > TIL' 카테고리의 다른 글

프로젝트 회고  (0) 2024.12.18
Open Route Service API 사용  (1) 2024.12.16
DDD(Domain-Driven Design)  (1) 2024.12.09
SAGA 패턴  (1) 2024.12.07
Kafka - 기초  (0) 2024.12.06