JAVA

Lombok @Getter(Class Level) Ignore Stragegy - 오버라이드 된 메소드와 대소문자를 구분하지 않고 중복 비교

유혁스쿨 2024. 6. 14. 01:19
728x90
반응형

상황은 이러하다.

User 클래스에 userName 이라는 이름의 private 인스턴스 멤버를 선언하고 해당 클래스 레벨에 @Getter를 적용하였다.

(필드 레벨에는 이러한 현상이 발생하지 않는다.)

또한 해당 User클래스는 Security에서 지원하는 UserDetails 인터페이스를 구현하였고 getUsername() 메소드를 오버라이딩 하였다.

@Getter
@Setter
public class User implements UserDetails {
    private String userName; // 롬복의 @Getter에 의해 getUserName() 생성
    
    @Override
    public String getUsername() {
    	return this.userName;
    }
}

 

이후 특정 클래스를 생성하여 해당 User 인스턴스 객체로부터 UserDetails를 구현하여 오버라이딩 한 getUsername() 메소드와 Lombok에 의해 생성된 User의 인스턴스 필드의 getter인 getUserName()을 각각 호출하였다.

public class Example {
    public void access() {
    	User user = new User();
        user.getUsername(); // 정상
        user.getUserName(); // IDE에서 메소드를 호출하지 못한다 (롬복에서 무시됨)
    }
}

 

여기서 발생한 오류는 인터페이스를 구현한 Overriding된 getUsername() 메소드는 정상적으로 호출되었으나, User의 인스턴스 멤버인 userName에 대한 Lombok이 적용된 getter 메소드 getUserName()은 호출되지 않았다. (정의되지 않음..)

 

이에 다음 두가지 유추를 해봤다.

  1. Spring Security에 의해 UserDetails를 구현한 클래스의 username 필드만 제한적으로 처리되는가? 
  2. Reflection에 의해 컴파일 시점에 메소드의 대소문자를 구분하여 중복을 체크하는가?

 

조금 더 자세히 알아보려고 노력했더니, 두번째 유추와 근접한 내용을 알게 되었다.

Lombok은 내부적으로 @Getter가 적용된 클래스의 인스턴스 필드의 getter 메소드를 생성할 때 구현한 인터페이스의 모든 메소드를 기준으로 @Getter가 적용된 모든 필드의 getter메소드의 메소드명을
대/소문자 구분 없이 비교하여 Overriding되어 있다면 Lombok에서 무시한다는 사실을 알게 되었다.

 

1.handle() : lombok/src/core/lombok/javac/handlers/HandleGetter.java [Line127]

  • 153Line의 createGetterForFields() 호출

https://github.com/projectlombok/lombok/blob/master/src/core/lombok/javac/handlers/HandleGetter.java#L127

 

lombok/src/core/lombok/javac/handlers/HandleGetter.java at master · projectlombok/lombok

Very spicy additions to the Java programming language. - projectlombok/lombok

github.com

 

2. createGetterForField() : lombok/src/core/lombok/javac/handlers/HandleGetter.java [Line162]

  • Line202에서 methodExists() 메소드를 호출

https://github.com/projectlombok/lombok/blob/master/src/core/lombok/javac/handlers/HandleGetter.java#L73

 

lombok/src/core/lombok/javac/handlers/HandleGetter.java at master · projectlombok/lombok

Very spicy additions to the Java programming language. - projectlombok/lombok

github.com

 

3. methodExists() : lombok/src/core/lombok/javac/handlers/EclipseHandlerUtil.java [Line1889]

 

lombok/src/core/lombok/eclipse/handlers/EclipseHandlerUtil.java at master · projectlombok/lombok

Very spicy additions to the Java programming language. - projectlombok/lombok

github.com

 

public static MemberExistsResult methodExists(String methodName, EclipseNode node, boolean caseSensitive, int params) {
    while (node != null && !(node.get() instanceof TypeDeclaration)) {
        node = node.up();
    }
		
    if (node != null && node.get() instanceof TypeDeclaration) {
        TypeDeclaration typeDecl = (TypeDeclaration)node.get();
        if (typeDecl.methods != null) top: for (AbstractMethodDeclaration def : typeDecl.methods) {
            if (def instanceof MethodDeclaration) {
                char[] mName = def.selector;
                if (mName == null) continue;
                    boolean nameEquals = caseSensitive ? methodName.equals(new String(mName)) : methodName.equalsIgnoreCase(new String(mName));
                    if (nameEquals) {
                        if (params > -1) {
                            int minArgs = 0;
                            int maxArgs = 0;
                            if (def.arguments != null && def.arguments.length > 0) {
                                minArgs = def.arguments.length;
                                if ((def.arguments[def.arguments.length - 1].type.bits & ASTNode.IsVarArgs) != 0) {
                                    minArgs--;
                                    maxArgs = Integer.MAX_VALUE;
                                } else {
                                    maxArgs = minArgs;
                                }
                            }
							
                            if (params < minArgs || params > maxArgs) continue;
                        }
                        if (isTolerate(node, def)) continue top;
                        return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK;
                    }
                }
            }
        }
        return MemberExistsResult.NOT_EXISTS;
    }
}

 

 

boolean nameEquals = caseSensitive ? methodName.equals(new String(mName)) : methodName.equalsIgnoreCase(new String(mName));
if (nameEquals) {
    if (params > -1) {
        int minArgs = 0;
        int maxArgs = 0;
        if (def.arguments != null && def.arguments.length > 0) {
            minArgs = def.arguments.length;
            if ((def.arguments[def.arguments.length - 1].type.bits & ASTNode.IsVarArgs) != 0) {
                minArgs--;
                maxArgs = Integer.MAX_VALUE;
            } else {
                maxArgs = minArgs;
            }
        }

        if (params < minArgs || params > maxArgs) continue;
    }
    if (isTolerate(node, def)) continue top;
    return getGeneratedBy(def) == null ? MemberExistsResult.EXISTS_BY_USER : MemberExistsResult.EXISTS_BY_LOMBOK;
}

 

 

이러한 현상은 Abstract 추상 클래스의 추상메소드 또한 동일하게 적용된다

728x90
반응형