Json 2차원 배열 에러

Nam_JU·2022년 5월 15일
0

Spring

목록 보기
8/11
post-custom-banner

배경

모모프로젝트의 댓글기능을 구현하다가 JSON응답 형식을 보니 프론트분들이 보기 힘들겠다는 생각이 들어 변경하고 싶었다. 내가 원했던 방식은 이차배열로 객체 안에 배열이 들어가 보기 좋게 나열되는 형태였다


수정전 응답 형태

저 댓글 객체 안에 topic , post 정보가 들어가길 원했다

image

Json 2차원 배열 에러

프로젝트 ERD를 보면 Topic - Post가 서로 양방향 연관관계이다
Topic안에는 PostEntityList가 들어가 있는데 이게 무한 참조되어 값이 불러와진것을 볼 수 있었다

TopicEntity

@Builder
@Entity
@AllArgsConstructor
@NoArgsConstructor
@Data
@Table(name = "topic")
public class TopicEntity extends BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long tid;

    private String title;


    @OneToMany(
            fetch = FetchType.LAZY,
            targetEntity = PostEntity.class,
            mappedBy = "topicEntity"
    )
    private List<PostEntity> postEntityList = new ArrayList<>();
    
--> postEntityList가 계속 참조되어서 에러


}

CommentDto

원래는 단일로 Long타입의 PostId를 반환값으로 나타내주었는데 객체를 반환해 주기 위해 PostDto타입으로 변경하였다

@Builder //package-private 생성자가 자동으로 생성
@AllArgsConstructor //모든 필드 값을 파라미터로 받는 생성자를 만들어준다
@NoArgsConstructor //파라미터가 없는 기본 생성자를 생성
@Data
public class CommentDto {

    @ApiModelProperty(value = "고유 id")
    private Long id;

    @ApiModelProperty(value = "댓글" , example = "댓글: 정말 좋아보여요")
    private String comment;

    private Instant createAt;
    private Long userId;
    private PostDto postDto; // 원래는 Long postId; 였다
    

}

수정전 CommentService 코드

 @Override
    public CommentDto create(Long postId, CommentDto dto) {
        if (!this.postRepository.existsById(postId))
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        if (!this.userRepository.existsById(dto.getUserId()))
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);

        PostEntity postEntity = this.postRepository.findById(postId).get();
        UserEntity userEntity = this.userRepository.findById(dto.getUserId()).get();

        CommentEntity commentEntity = new CommentEntity();
        commentEntity.setComment(dto.getComment());

        commentEntity.setWriter(userEntity);
        commentEntity.setPostEntity(postEntity);
        commentEntity = this.commentRepository.save(commentEntity);

        return new CommentDto(
                commentEntity.getCid(),
                commentEntity.getComment(),
                commentEntity.getCreateAt(),
                commentEntity.getPostEntity(),
                commentEntity.getWriter().getUid()
        );
    }


해결 방법

CommentService 코드에 PostEntity를 바로 반환시키지 않고 PostDto객체를 만들어 반환하고자 하는 값을 넣어 원하는 형태로 반환시켜준다


CommentService

commentEntity.setPostEntity(postEntity); 부분을 없애고 DTO객체를 만들어 값을 넣어준다

    @Override
    public CommentDto create(Long postId, CommentDto dto) {

        if (!this.postRepository.existsById(postId))
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);
        if (!this.userRepository.existsById(dto.getUserId()))
            throw new ResponseStatusException(HttpStatus.NOT_FOUND);

        PostEntity postEntity = this.postRepository.findById(postId).get();
        UserEntity userEntity = this.userRepository.findById(dto.getUserId()).get();

        CommentEntity commentEntity = new CommentEntity();
        commentEntity.setComment(dto.getComment());

        commentEntity.setWriter(userEntity);
//        commentEntity.setPostEntity(postEntity);  -> 원래는 이 방식이었지만 JSON 2차 배열방식으로 반환되길 원해서 수정
        commentEntity = this.commentRepository.save(commentEntity);

        /**
         JSON 2차 배열로 POST객체 값을 배열형태로 가져오고 싶음!
         Topic Entity의 PostEntitiyList가 계속 무한 참조됨으로
         Entity를 가져오지 말고 DTO에 담아서 가져오자
         * */
         
        PostDto postDto = new PostDto();
        postDto.setId(postEntity.getPid());
        postDto.setContent(postEntity.getContent());
        postDto.setUserId(postEntity.getWriter().getUid());
        postDto.setTopicId(postEntity.getTopicEntity().getTid());
        postDto.setTopicTitle(postEntity.getTopicEntity().getTitle());
        postDto.setCreateAt(postEntity.getCreateAt());


        return new CommentDto(
                commentEntity.getCid(),
                commentEntity.getComment(),
                commentEntity.getCreateAt(),
                commentEntity.getWriter().getUid(),
                postDto
        );
    }


원하는 형태로 잘 나타나졌다!


코드 개선 Builder 패턴

위의 코드를 고치면서 코드가 너무 길다 비효율적으로 보인다 라는 생각이 들었다. 언뜻 듣기만하고 제대로 사용해본적 없는 builder패턴이라는 것을 적용해보자!


빌더 패턴이란? Builder Pattern

빌더 패턴은 복잡한 객체를 생성하는 클래스와 표현하는 클래스를 분리하여, 동일한 절차에서도 서로 다른 표현을 생성하는 방법을 제공한다.

원래는 클래스를 분리해서 사용하는 것인데 현재 클래스 자체를 변경하기에는 시간적 여유와 대공사가 될것임을 깨닫고 아쉬운대로 빌더 부분만 적용시키기로 했다

        /**
         JSON 2차 배열로 POST객체 값을 배열형태로 가져오고 싶음!
         Topic Entity의 PostEntitiyList가 계속 무한 참조됨으로
         Entity를 가져오지 말고 DTO에 담아서 가져오자
         * */
         
         
// 빌더 적용 전         
        PostDto postDto = new PostDto();
        postDto.setId(postEntity.getPid());
        postDto.setContent(postEntity.getContent());
        postDto.setUserId(postEntity.getWriter().getUid());
        postDto.setTopicId(postEntity.getTopicEntity().getTid());
        postDto.setTopicTitle(postEntity.getTopicEntity().getTitle());
        postDto.setCreateAt(postEntity.getCreateAt());


// 빌더 적용
PostDto postDto = PostDto.builder()
                .id(postEntity.getPid())
                .content(postEntity.getContent())
                .userId(postEntity.getWriter().getUid())
                .topicId(postEntity.getTopicEntity().getTid())
                .topicTitle(postEntity.getTopicEntity().getTitle())
                .build();



        return new CommentDto(
                commentEntity.getCid(),
                commentEntity.getComment(),
                commentEntity.getCreateAt(),
                commentEntity.getWriter().getUid(),
                postDto
        );

코드가 더 깔끔해진것을 볼 수 있다!



새벽 1시까지 같이 공부하고 의견을 주신 스터디 메이트님께 영광을...!

profile
개발기록
post-custom-banner

0개의 댓글