얼마 전 Eclipse Mars가 출시하고, 스프링에서는 이클립스 마르스를 얹은 STS.3.7.0 버전을 내놓았다.

나는 지금까지 개발할 때 Lombok을 많이 사용해왔다. 클래스 내 필드에 대한 Getter/Setter 생성이나 toString(), equals(), hashCode() 메서드를 오버라이드 하기 위해 클래스에 코드가 덕지덕지 붙는 것을 어노테이션들(@ToString,@EqualsAndHashCode, @Getter, @Setter, @Data 등)로 대신할 수 있기 때문이다. 자바로 개발할 때 겪게되는 반복적이고 가독성에 크게 도움되지 않는 녀석들을 컴파일과정에서 어노테이션을 기반으로 하여 자동생성해주기에 코드가 그나마 많이 간결해진다.

그런데!! 이클립스 루나까지는 크게 문제가 없던 STS(3.6.0)에서 3.7.0으로 버전업을 하고 난 이후에 몇몇 결함이 발생한다. 예를 들어,

  • 현재 열고 있는 클래스에 대한 유닛테스트를 위해 클래스를 만들려고 하면 비어있는 파일만 생성하기
  • Getter/Setter 생성시 원인모를 예외를 발생시키기
  • 인스턴스 메서드에서 던지는 throws Exception 을 메서드에 반영하지 못함
  • 구현하고 있는 인터페이스에 메서드를 생성하지 못함

등... 개발하는 과정에서 자주하는 일들을 할 수가 없는 것은, 가뜩이나 좋지 않은, 생산성을 뚜욱하고 떨어뜨리는 슬픈 상황을 만들었다. 그래도 투덜거리면서 쓰다가,

투걸거리지만 말고, 버그 리포팅을 해서 개선할 수 있도록 해주세요.

간단하게 Getter/Setter를 만드는 작업을 진행해보면 다음과 같은 증상이 나온다.





  • 에러코드
eclipse.buildId=3.7.0.201506290652-RELEASE-e45
java.version=1.8.0_20
java.vendor=Oracle Corporation
BootLoader constants: OS=linux, ARCH=x86_64, WS=gtk, NL=ko_KR
Framework arguments:  -client -product org.springsource.sts.ide
Command-line arguments:  -os linux -ws gtk -arch x86_64 -client -product org.springsource.sts.ide -console
 
java.lang.reflect.InvocationTargetException
    at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:476)
    at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:371)
    at org.eclipse.ui.internal.WorkbenchWindow$14.run(WorkbenchWindow.java:2156)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
    at org.eclipse.ui.internal.WorkbenchWindow.run(WorkbenchWindow.java:2152)
    at org.eclipse.ui.internal.progress.ProgressManager$RunnableWithStatus.run(ProgressManager.java:1394)
    at org.eclipse.swt.custom.BusyIndicator.showWhile(BusyIndicator.java:70)
    at org.eclipse.ui.internal.progress.ProgressManager$5.run(ProgressManager.java:1228)
    at org.eclipse.swt.widgets.Synchronizer.syncExec(Synchronizer.java:186)
    at org.eclipse.ui.internal.UISynchronizer.syncExec(UISynchronizer.java:145)
    at org.eclipse.swt.widgets.Display.syncExec(Display.java:4633)
    at org.eclipse.ui.internal.progress.ProgressManager.runInUI(ProgressManager.java:1225)
    at org.eclipse.jdt.ui.actions.AddGetterSetterAction.run(AddGetterSetterAction.java:618)
    at org.eclipse.jdt.ui.actions.AddGetterSetterAction.generate(AddGetterSetterAction.java:549)
    at org.eclipse.jdt.ui.actions.AddGetterSetterAction.run(AddGetterSetterAction.java:340)
    at org.eclipse.jdt.ui.actions.AddGetterSetterAction.run(AddGetterSetterAction.java:584)
    at org.eclipse.jdt.ui.actions.SelectionDispatchAction.dispatchRun(SelectionDispatchAction.java:279)
    at org.eclipse.jdt.ui.actions.SelectionDispatchAction.run(SelectionDispatchAction.java:251)
    at org.eclipse.jface.action.Action.runWithEvent(Action.java:473)
    at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection(ActionContributionItem.java:595)
    at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContributionItem.java:511)
    at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionContributionItem.java:420)
    at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
    at org.eclipse.swt.widgets.Display.sendEvent(Display.java:4481)
    at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1327)
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3819)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3430)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$4.run(PartRenderingEngine.java:1127)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
    at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1018)
    at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:156)
    at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:654)
    at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:337)
    at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:598)
    at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
    at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:139)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:380)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:235)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:669)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:608)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1515)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1488)
Caused by: java.lang.IndexOutOfBoundsException: Index: 5, Size: 5
    at java.util.ArrayList.rangeCheck(ArrayList.java:653)
    at java.util.ArrayList.get(ArrayList.java:429)
    at org.eclipse.jdt.internal.formatter.TokenManager.get(TokenManager.java:68)
    at org.eclipse.jdt.internal.formatter.TokenManager.findIndex(TokenManager.java:161)
    at org.eclipse.jdt.internal.formatter.TokenManager.firstIndexIn(TokenManager.java:188)
    at org.eclipse.jdt.internal.formatter.TokenManager.firstTokenIn(TokenManager.java:194)
    at org.eclipse.jdt.internal.formatter.SpacePreparator.visit(SpacePreparator.java:196)
    at org.eclipse.jdt.core.dom.MethodDeclaration.accept0(MethodDeclaration.java:611)
    at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2711)
    at org.eclipse.jdt.core.dom.ASTNode.acceptChildren(ASTNode.java:2782)
    at org.eclipse.jdt.core.dom.TypeDeclaration.accept0(TypeDeclaration.java:470)
    at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2711)
    at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareSpaces(DefaultCodeFormatter.java:350)
    at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.prepareFormattedCode(DefaultCodeFormatter.java:193)
    at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.format(DefaultCodeFormatter.java:155)
    at org.eclipse.jdt.internal.formatter.DefaultCodeFormatter.format(DefaultCodeFormatter.java:139)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.formatString(ASTRewriteFormatter.java:246)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.formatNode(ASTRewriteFormatter.java:376)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteFormatter.getFormattedResult(ASTRewriteFormatter.java:187)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doTextInsert(ASTRewriteAnalyzer.java:1357)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer$ListRewriter.rewriteList(ASTRewriteAnalyzer.java:647)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer$ListRewriter.rewriteList(ASTRewriteAnalyzer.java:802)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.rewriteParagraphList(ASTRewriteAnalyzer.java:1175)
    at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1811)
    at org.eclipse.jdt.core.dom.TypeDeclaration.accept0(TypeDeclaration.java:453)
    at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2711)
    at org.eclipse.jdt.core.dom.rewrite.ASTRewrite.internalRewriteAST(ASTRewrite.java:302)
    at org.eclipse.jdt.core.dom.rewrite.ASTRewrite.rewriteAST(ASTRewrite.java:291)
    at org.eclipse.jdt.internal.corext.codemanipulation.AddGetterSetterOperation.run(AddGetterSetterOperation.java:351)
    at org.eclipse.jdt.internal.core.BatchOperation.executeOperation(BatchOperation.java:39)
    at org.eclipse.jdt.internal.core.JavaModelOperation.run(JavaModelOperation.java:729)
    at org.eclipse.core.internal.resources.Workspace.run(Workspace.java:2241)
    at org.eclipse.jdt.core.JavaCore.run(JavaCore.java:5409)
    at org.eclipse.jdt.internal.ui.actions.WorkbenchRunnableAdapter.run(WorkbenchRunnableAdapter.java:106)
    at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalContext.java:463)
    ... 48 more

라고 올챙이 프로젝트(https://github.com/hangum/TadpoleForDBTools)를 지휘하고 계시는 조현종님이 말씀하시기에 '그래, 버그를 수정할 수 있도록 돕자'하는 마음에 이클립스의 'Error View'를 열고 이클립스에서 생긴 예외상황을 찾아봤다. 그리고 이 것을 SNS에 올리니까

그거 롬복 때문에 생긴 문제에요. 롬복 최신버전 받으면 정상적으로 동작해요.

라고 지인(http://sbcoba.tistory.com/)이 알려주었다. 이 때 찾아드는 허무감이란... 요 근래에 개발환경에 큰 변화가 찾아오기는 했다.

  • JDK 7 -> JDK 8
  • Eclipse Luna -> Eclipse Mars

이런 변화를 간과하고 이클립스만 탓한 내가 부끄러워지는구나.... 사용하고 있던 롬복은 v1.14.8 버전이다. 현재(2015/08/27) project lombok에서 다운로드 가능한 버전은1.16.6(https://projectlombok.org/changelog.html)이다. 8월 16일에 반영된 내용을 살펴보니

이다. 이클립스 마르스와 관련해서 버그가 있었던 것이었다. 최신버전 받으면 해결된다. 혹은... 롬복을 사용하지 않으면 된다.


intellij 12.1.5 버전에서 컴파일과 관련한 문제로 Lombok이 제대로 동작하지 않는 기현상을 보였다. 이에 jetbrain에서는 급히 컴파일 문제를 해결한 12.1.6 으로 업그레이드버전을 제공했다. 그런데 이녀석으로 업그레이드를 한 이후에 계속 컴파일 중에 오류가 발생한다.


로그에서 'ajc: the method ...' 라고 하는 메시지를 출력하며, Lombok annotation을 사용한 클래스가 정상적으로 컴파일 되지 않았다.

Lombok의 annotation이 컴파일시에 제대로 동작하지 않아서 생기는 문제가 아닐까 하고 Lombok plugin 재설치를 몇번해보고 설정에서 Compiler - Annotation Processors 에서 'Enable annotation processing'을 체크했다가 해제했다가를 반복했지만 증상은 똑같았다.

인터넷 검색을 해도 딱히 답이 나오지 않던 상황...

불현듯 '컴파일러!' 가 떠오르면서 'Compiler - Java Compiler' 를 찾아 들어갔다. 

'Use Compiler' 에 보니까 내가 모르는 Ajc가 선택되어 있다.

컴파일러를 'javac' 로 변경하고 나니 정상적으로 컴파일되고 배포까지 완료되었다...!! 두둥!

로그 속에 답이 있다는 진리를 새삼 깨닫다.


 

 정리

 

Intellij 12.1.6 업그레이드 후에도 Lombok 이 정상동작 하지 않을 시,

  • 이동: [Settings...] - [Compiler] - [Java Compiler]
  • 변경: 'User Compiler' - javac 로 변경



... Default는 javac라면서? 난... Compiler 변경한 적 없다!!

+ Recent posts