문제상황
개발하면서 특정 정보를 필터링할 Predicate를 동적으로 생성하고 싶은 마음에 다음과 같이 개발을 진행했었다.
WedulFilterPredicate
- 필터로 사용할 조건을 보관하고 Predicate를 반환하는 클래스
package com.wedul.springtest;
import lombok.Builder;
import lombok.Getter;
import java.util.function.Predicate;
@Getter
public class WedulFilterPredicate {
private Boolean hasName;
private Boolean hasPicture;
private String teamNo;
@Builder
public WedulFilterPredicate(Boolean hasName, Boolean hasPicture, String teamNo) {
this.hasName = hasName;
this.hasPicture = hasPicture;
this.teamNo = teamNo;
}
public Predicate createPredicate() {
if (hasPicture && teamNo != null) {
return data -> data.equals(teamNo);
}
return data -> false;
}
}
WedulFilter
- 조건별 필터(WedulFilterPredicate)를 생성할 수 있도록 static builder를 반환하는 메소드를 정의한 인터페이스
package com.wedul.springtest.filter;
import com.wedul.springtest.WedulFilterPredicate;
public interface WedulFilter {
WedulFilterPredicate.WedulFilterPredicateBuilder predicateBuilder();
}
WedulPosPredicate
- 조건 별 Enum value로 value에 따라 WedulFilterPredicate 클래스를 생성할 수 있도록 하는 static WedulFilterPredicateBuilder를 반환할 수 있도록 하는 enum 클래스
package com.wedul.springtest;
import com.wedul.springtest.filter.WedulFilter;
public enum WedulPosPredicate implements WedulFilter {
HAS_NAME {
@Override
public WedulFilterPredicate.WedulFilterPredicateBuilder predicateBuilder() {
return WedulFilterPredicate.builder()
.hasName(true);
}
},
HAS_PHOTOS {
@Override
public WedulFilterPredicate.WedulFilterPredicateBuilder predicateBuilder() {
return WedulFilterPredicate.builder()
.hasPicture(true);
}
}
}
WedulPosDomainService
- HAS_PHOTO조건에 맞는 Predicate를 WedulPosPredicate에서 받고 입력받은 teamNo를 사용하여 WedulFilterPredicate를 만들어서 predicate를 반환하는 서비스
package com.wedul.springtest;
import org.springframework.stereotype.Service;
import java.util.function.Predicate;
@Service
public class WedulPosDomainService {
public Predicate getHasPhotoWedulPosPredicate(String teamNo) {
WedulFilterPredicate wedulFilterPredicate = WedulPosPredicate.HAS_PHOTOS
.predicateBuilder()
.teamNo(teamNo)
.build();
return wedulFilterPredicate.createPredicate();
}
}
동일하지는 않지만 이런식으로 요청받은 filter값을 사용해서 Predicate를 생성하는 로직이었다. 크게 문제가 없이 동작할 것으로 보이지만 해당 코드를 돌려보면 error: cannot find symbol 에러가 발생한다.
/Users/jeongcheol/Documents/project/springtest/src/main/java/com/wedul/springtest/filter/WedulFilter.java:6: error: cannot find symbol
WedulFilterPredicate.WedulFilterPredicateBuilder predicateBuilder();
^
symbol: class WedulFilterPredicateBuilder
location: class WedulFilterPredicate
원인파악
위 코드에서 다른 부분이 중요한 것이 아니라 WedulFilter에서 WedulFilterPredicate.WedulFilterPredicateBuilder를 반환하고 있는 이부분에서 WedulFilterPredicateBuilder를 못찾는다는 것이다.
왜 못찾는 것인가? 그냥 봤을때는 lombok의 builder 애노테이션을 사용하게 되면 static 클래스를 생성해서 접근해서 사용할 수 있도록 하기 때문에 큰 문제가 없을거라고 생각하게된다. 실제 Delombok을 해서 생성되는 코드를 봐도 WedulFilterPredicateBuilder클래스가 만들어져서 큰 문제없이 접근이 가능할것이라고 보인다.
public static class WedulFilterPredicateBuilder {
private Boolean hasName;
private Boolean hasPicture;
private String teamNo;
WedulFilterPredicateBuilder() {
}
public WedulFilterPredicateBuilder hasName(Boolean hasName) {
this.hasName = hasName;
return this;
}
public WedulFilterPredicateBuilder hasPicture(Boolean hasPicture) {
this.hasPicture = hasPicture;
return this;
}
public WedulFilterPredicateBuilder teamNo(String teamNo) {
this.teamNo = teamNo;
return this;
}
public WedulFilterPredicate build() {
return new WedulFilterPredicate(hasName, hasPicture, teamNo);
}
public String toString() {
return "WedulFilterPredicate.WedulFilterPredicateBuilder(hasName=" + this.hasName + ", hasPicture=" + this.hasPicture + ", teamNo=" + this.teamNo + ")";
}
}
하지만 동작하지 않았던 원인은 lombok의 동작방식을 보면 알 수 있는데 lombok을 사용할 때 AnnotationProcessor를 사용해서 코드를 생성해서 사용한다는것을 알고 있다.
하지만 static import는 annotation processor가 동작하기전에 진행되기 때문에 javac 컴파일 시점에 WedulFilterPredicateBuilder를 찾지 못하기 때문에 발생하는 문제였다.
해결방법
WedulFilterPredicateBuilder static class 미리 생성
위 에러의 문제가 static import 작업 시 lombok의 생성내용을 알지 못하기 때문에 발생하는 것으로 lombok이 생성하는 static class 껍데기를 미리 생성하는 것이다. 그럼 의문이 들수 있는 부분이 나중에 Lombok이 코드를 생성할 때 문제가 되는거 아니야? 라고 생각할 수 있다. 하지만 실제 롬복에 의해서 코드가 생성되는 시점에 해당 클래스에 내용물을 채워지기 때문에 동작에 문제가 없다.
package com.wedul.springtest;
import lombok.Builder;
import lombok.Getter;
import java.util.function.Predicate;
@Getter
public class WedulFilterPredicate {
private Boolean hasName;
private Boolean hasPicture;
private String teamNo;
@Builder
public WedulFilterPredicate(Boolean hasName, Boolean hasPicture, String teamNo) {
this.hasName = hasName;
this.hasPicture = hasPicture;
this.teamNo = teamNo;
}
public static class WedulFilterPredicateBuilder {}
public Predicate createPredicate() {
if (hasPicture && teamNo != null) {
return data -> data.equals(teamNo);
}
return data -> false;
}
}
http://www.miredot.com/docs/faq/q/cannot-find-symbol-during-javadoc-phase/
https://github.com/projectlombok/lombok/issues/979
https://stackoverflow.com/questions/47674264/static-import-not-working-in-lombok-builder-in-intellij
'web > Spring' 카테고리의 다른 글
dynamoDbEnhancedClient에서 QueryConditional에서 sort key range 조회하기 (0) | 2022.11.04 |
---|---|
Dynamodb enhanced client (0) | 2022.07.24 |
Gradle build 시 node js 버전을 지정하여 빌드하기 (3) | 2022.04.23 |
S3Mock을 사용한 S3 테스트 방법 (0) | 2022.03.08 |
만들면서 배우는 아키텍처 그리고 매핑 프레임워크 MapStruct를 사용한 매핑 (0) | 2022.02.02 |