상황

  • SpringBoot에서 MongoDB에 데이터를 저장하고, 저장한 데이터를 파싱하는 과정에서 다음과 같은 오류가 발생했습니다.

  • 실행 코드

// 몽고DB 컬렉션 클래스
@Document(collection = "indicators")
@Getter
@NoArgsConstructor
@Builder
@AllArgsConstructor
@Slf4j
public class Indicator {
    @Id
    private String id;
    private List<MatchIndicator> matchIndicators;
    private MatchIndicatorStatistics matchIndicatorStatistics;

    // 메서드 생략
}

// 컬렉션 조회 메서드
    @Override
    public Indicator getIndicatorInDB(String SummonerId) {
        Query query = Query.query(
                Criteria.where("_id").is(SummonerId));

        Indicator indicators = mongoTemplate.findOne(query, Indicator.class, "indicators");

        if (indicators == null) throw new RiotDataException(RiotDataError.NOT_IN_STATISTICS_DATABASE);
        else log.info("indicator founded : {}", indicators.getId());

        return indicators;
    }
  • 오류 코드
Parameter org.springframework.data.mapping.Parameter@691d29ad does not have a name

원인 분석

실제로 MongoDB에서 데이터를 정상 꺼내오는 로그는 다음과 같이 잘 찍혀있었습니다.

Command "find" succeeded on database "matchup_statistics_db" in 1.627834 ms using a connection with driver-generated ID 3 and server-generated ID 321 to localhost:3311. The request ID is 6 and the operation ID is 5. Command reply: {"cursor": {"firstBatch": [{"_id": // 생략

또한, 이미 MongoDB에 데이터를 저장할 때는 문제없이 저장되었던 값을 꺼내오는 과정에서 오류가 발생했기 때문에, 꺼내온 값을 spring에서 mapping하는 과정에서 특정 파라미터를 인식하지 못해 발생했다고 생각했습니다.

해결

1. 기본 생성자 추가

  • Spring에서 사용하는 mapping은 기본적으로 생성자를 통해 객체를 Reflection하기 때문에, 기본 생성자를 추가해야 합니다.(혹은 lombok의 @NoArgsConstructor)

해당 Collection의 Field에 들어가는 모든 클래스에 기본 생성자를 붙여주었지만 동일한 오류가 계속 발생했습니다.

2. @Field 추가

  • MongoDB에서 객체를 생성해서 가져오는 과정에서 해당 어노테이션이 없으면 인식을 못해서 org.springframework.data.mapping.PropertyReferenceException 가 발생할 수 있다고 합니다.1

저와 다른 종류의 오류이기도 하고, 저는 해당 어노테이션 없이 해결이 되었지만 혹시 해결되지 않는 분들은 적용해보시기 바랍니다.

3. Build Option : Intellij -> Gradle로 변경

  • 해당 코드를 디버깅하면 다음 소스코드에서 null이 발생함을 알 수 있습니다.
@Nullable
private String[] getParameterNames(Parameter[] parameters) {
    String[] parameterNames = new String[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        Parameter param = parameters[i];
        if (!param.isNamePresent()) {
            return null; // null 발생
        }
        parameterNames[i] = param.getName();
    }
    return parameterNames;
}

즉, 빌드 시점에 파라미터가 설정되지 않아 발생하는 문제이며 이는 Gradle로 실행 시 자동으로 해결됩니다. 자세한 설명은 해당 블로그를 참고하시기 바랍니다.

저는 인텔리제이에서 빌드 옵션을 변경했더니 정상 실행이 되었습니다.

Intellij에서 Gradle로 변경합니다.

Intellij에서 Gradle로 변경합니다.

오류의 원인이 단순히 코드에만 있는 게 아니라, 프레임워크나 IDE등에 의해서도 충분히 발생할 수 있음을 항상 견지해야겠습니다. 그리고 프레임워크의 의존성을 줄여나가는 것도 좋은 방향이라고 생각합니다.

References

URL게시일자방문일자작성자
https://ricma.co/posts/tech/dev/migrating-to-spring-61-javac-parameters2023.09.22.2024.04.02.Riccardo Macoratti
https://stackoverflow.com/questions/36160919/caused-by-org-springframework-data-mapping-model-mappingexception-no-property2016.03.22.2024.04.02.user4821194
https://stackoverflow.com/questions/53207049/spring-data-mongo-no-property-b-found-on-entity-class-when-retrieving-entity-by/53210768#532107682018.11.08.2024.04.02.J.Pip