PropertyReferenceException: No property found for type 발생 원인과 해결 방법
작업 중 'PropertyReferenceException: No property found for type' 예외가 발생하였고, 원인을 찾는데 한 시간이 넘게 걸렸지만 원인은 결국 아주 사소한 것(오타)이었는데요.
jpa, querydsl을 사용하며 생각보다 자주 만날 수 있는 오류인 것 같았으며, 발생한 케이스 외에도 몇 가지 비슷한 경우가 있어 함께 정리한 내용입니다.
(아래 예시에서 사용된 NoticeMember는 단순 예시를 위한 Entity 명입니다.)
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property 'getNoticeMemberList' found for type 'NoticeMember'
1. RepositoryImpl 클래스명 오타
//Repository
public interface NoticeMemberRepository extends JpaRepository<NoticeMember, Long>, NoticeMemberRepositoryCustom {
...
}
//RepositoryCustom
public interface NoticeMemberRepositoryCustom {
...
}
//RepositoryImpl
public class NoticeMemberRepositoryImpl implements NoticeMemberRepositoryCustom {
...
}
예외가 발생했던 원인이자 첫 번째 케이스입니다.
querydsl을 사용할 때는 다음과 같이 {Entity명}Repository, {Entity명}RepositoryCustom, {Entity명}RepositoryImpl의 구조로 인터페이스 및 클래스를 생성하는데요.
Custom 인터페이스의 경우 다른 이름이 되어도 상관이 없지만, 실제 해당 메서드가 구현되는 Impl 클래스의 경우 '{Entity명}RepositoryImpl' 이라는 이름으로 생성되어야 한다는 규칙이 있습니다.
(제가 오류가 발생했던 원인은 생성된 Impl 클래스의 이름이 NoticeMemberRepositoryImpl이 아닌 NoticeMemberImpl으로 Repository를 빼먹어서였습니다.)
2. 카멜 케이스(camelCase)로 인한 오류
//Repository
public interface NoticeMemberRepository extends JpaRepository<NoticeMember, Long>, NoticeMemberQuerydsl {
NoticeMember findByUsername(String username);
}
두 번째 케이스는 카멜 케이스(camelCase)로 인해 예외가 발생하는 경우입니다.
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Entity
public class NoticeMember {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_name")
private String userName;
...
}
예를 들어 Entity에 다음과 같이 userName이라는 필드가 있을 때, JpaRepository에서의 메서드 생성 규칙에 따라 카멜 케이스가 적용된 findByUserName(String userName)와 같은 형식으로 메서드를 생성해야 합니다.
하지만 위 예시에서의 메서드는 UserName이 아닌 Username으로 카멜 케이스가 제대로 적용되지 않았는데요.
이러한 경우 아래와 같이 No property 'username' found for type 'NoticeMember'; Did you mean 'userName'라는 메시지를 통해 userName을 쓰는 것이 맞는 것 같다고 알려줍니다.
//Repository
public interface NoticeMemberRepository extends JpaRepository<NoticeMember, Long>, NoticeMemberQuerydsl {
NoticeMember findbyUserName(String userName);
}
비슷한 오류로 findBy 같이 jpa에서 지원되는 쿼리 메서드에 사용되는 규칙을 findby 등으로 잘못 만드는 경우에도 PropertyReferenceException: No property found for type 예외가 발생할 수 있습니다.
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords
(jpa repository에서 지원되는 쿼리 메서드의 키워드는 위 공식 문서에서 확인할 수 있습니다.)
3. 존재하지 않는 필드명을 사용한 쿼리 메서드를 만들었을 때
//Repository
public interface NoticeMemberRepository extends JpaRepository<NoticeMember, Long>, NoticeMemberQuerydsl {
NoticeMember findByPrice(Long price);
}
세 번째 케이스는 Entity에 존재하지 않는 필드를 사용하여 쿼리 메서드를 만들었을 때 발생하는 경우입니다.
NoticeMember Entity에 price 필드가 존재하지 않는 상황에서 위 코드와 같이 repository 인터페이스에 findByPrice()와 같은 메서드를 생성하는 경우에도 No property 'price' found for type 'NoticeMember'과 같은 오류가 발생하게 됩니다.
여기까지 jpa, querydsl을 사용하며 만날 수 있는 PropertyReferenceException 예외 상황 몇 가지와 해결 방법에 대해서 살펴봤는데요. 내용 중 잘못된 부분이나 궁금하신 부분은 댓글 달아주시면 확인 후 답변드리겠습니다. 감사합니다.
< 참고 자료 >
https://stackoverflow.com/questions/19583540/spring-data-jpa-no-property-found-for-type-exception
https://www.baeldung.com/spring-data-jpa-exception-no-property-found-for-type