Dev

IntelliJ의 Groovy Console 소개

prostars 2025. 3. 4. 14:12

오래전에 'IntelliJ 의 JShell Console 을 활용하자’ 라는 포스팅을 했다.

이번에는 'IntelliJ의 Groovy Console’을 소개한다. 이 글은 Java 환경에서 JShell 대신 Groovy Console 사용하는 방법을 설명한다.

 

이 내용은 제 온라인 강의에서 파트 2-챕터 1 '테스트에 대한 이야기 있는 '04. Groovy Console 소개’ ’05. Spock 사용을 위한 Groovy 기본 문법’ 2개의 영상에 있는 내용 중에서 'Groovy 기본 문법 대한 내용은 제외하고 'Groovy Console' 대해서 일부 글로 정리한 것으로, Groovy Console에서 자바 문법을 사용하여 진행하므로 Groovy를 몰라도 무방하다.

글의 말미에 Java Lambda 받는 Java 객체에 Groovy Closure 사용할 있는지 확인하는 코드에만 Groovy 문법을 한번 사용한다.

코드는 모두 GitHub에 올라가 있다.

 

Java New Project 생성

먼저 IntelliJ에서 프로젝트를 하나 생성한다.

 

이번 예제에서 Main.java 파일은 사용하지 않으니 삭제한다.

 

Groovy Console 실행

IntelliJ 2024.3 버전 기준으로 Groovy 플러그인이 기본으로 활성화된 상태로 추가 설정 없이 Groovy Console을 바로 사용할 수 있다.

다만, IntelliJ의 도움말 문서 'Interactive Groovy console'에는 현재 열려있는 프로젝트 종속성에 Groovy 라이브러리가 포함되어 있지 않은 상태로 그루비 콘솔을 사용하면 번들로 제공되는 2.3.9 버전의 Groovy 가 사용될 수 있다고 설명되어 있다.

여기서 사용할 코드는 Groovy 최신 버전이 필요하지 않으니, IntelliJ 번들로 제공하는 Groovy 그대로 사용한다.

 

IntelliJ 기본 제공하는 Groovy Console 아래 스크린샷에 보이는 것처럼 Main Menu에서 Tools 'Groovy Console’이라는 메뉴명을 선택하여 실행할 있다.

'Groovy Console’이라는 메뉴를 선택하여 실행하면 아래 스크린샷에 보이는 것처럼 'groovy_console.groovy’라는 파일명을 기본값으로 하여 파일이 하나 열린다. 파일 탭 아래에 있는 플레이 아이콘 옆에 ’Select Module...' 클릭해서 Groovy Console 사용할 클래스 패스를 선택할 있다.

여기 스크린샷에 보이는 것처럼 3개의 선택지에서 Groovy Console이 사용할 클래스 패스로 main 모듈의 클래스 패스를 선택한다.

선택하고 나면, 아래와 같이 설정이 적용된다.

이렇게 하면, 이제 Groovy Console에서 main 모듈에 있는 클래스를 사용할 수 있다.

다만, 소스 파일을 참조해서 사용하는 것이 아니라 클래스 패스에 있는 클래스 파일을 사용하는 것이라서 빌드가 먼저 되어있어야 한다.

그리고, 이 부분이 이전에 소개했던 'JShell Console’과 다른 부분이다.

'JShell Console’에서는 프로젝트의 클래스를 사용하려면 IntelliJ 프로젝트 설정에서 라이브러리 설정에 클래스 패스를 직접 등록해야 했지만, 'Groovy Console’은 이런 과정 없이 바로 사용할 수 있다.

 

먼저, Groovy Console이 정상 동작하는지 확인하기 위해서 간단히 'Hello World.'를 출력해 본다.

System.out.println("Hello World.")

위의 코드를 열려있는 Groovy Console 편집 창에 입력합니다. 세미콜론은 생략할 수 있다. 플레이 아이콘을 클릭하거나 단축키 Command + Enter (MacOS 기준)를 입력하면 실행된다. 실행하면 아래와 같은 실행 결과를 확인할 수 있다.

이제 Groovy Console에서 사용할 코드가 필요하니, 간단한 도서관 예제를 하나 구성하자.

// Book.java
package org.example;

public record Book(String isbn, String title, boolean available) {}

 

이 예제는 단독으로 실행할 프로젝트가 아니므로 BookRepository  PushService를 인터페이스로 간단히 정의한다.

// BookRepository.java
package org.example;

import java.util.Optional;

public interface BookRepository {
  Optional<Book> findBookByIsbn(String isbn);
}
// PushService.java
package org.example;

public interface PushService {
  void notification(String message);
}
// LibraryService.java
package org.example;

import java.util.Optional;

public class LibraryService {
  private final BookRepository bookRepository;
  private final PushService pushService;

  public LibraryService(BookRepository bookRepository, PushService pushService) {
    this.bookRepository = bookRepository;
    this.pushService = pushService;
  }

  public boolean isBookAvailable(String isbn) {
    return bookRepository
            .findBookByIsbn(isbn)
            .map(Book::available)
            .orElse(false);
  }

  public Optional<String> borrowBook(String isbn) {
    return bookRepository
        .findBookByIsbn(isbn)
        .filter(Book::available)
        .map(
            book -> {
              pushService.notification(
              	"대출 완료: " + book.title());
              return book.title();
            });
  }
}

이제 Groovy Console에서 사용해 클래스가 준비되었다.

 

위에도 언급했지만, BookRepository  PushService는 인터페이스만 있기에 지금 준비된 코드만으로는 LibraryService 바로 생성하여 사용할 없다. 하지만, Groovy Console 같은 REPL(Read-Eval-Print Loop) 빠른 프로토타이핑을 위해서 임시로 사용할 코드 조각을 바로 만들어서 사용해 있다.

 

코드로 확인해 보자.

이제 위에서 열었던 'groovy_console.groovy' 파일로 돌아가서, 아래의 코드를 입력한다.

import org.example.Book
import org.example.BookRepository
import org.example.LibraryService
import org.example.PushService

class BookRepositoryImpl implements BookRepository {
    @Override
    Optional<Book> findBookByIsbn(String isbn) {
        return Optional.of(
        	new Book("1234", "Groovy Console", true))
    }
}

class PushServiceImpl implements PushService {
    @Override
    void notification(String message) {
        System.out.println("pushed : " + message)
    }
}

BookRepository bookRepository = new BookRepositoryImpl()
PushService pushService = 
	new PushServiceImpl()
LibraryService libraryService = 
	new LibraryService(bookRepository, pushService)

String isbn = "1234"
if (libraryService.isBookAvailable(isbn)) {
    libraryService.borrowBook(isbn)
            .ifPresentOrElse(title -> 
            	System.out.println("대출 도서 : " + title),
                    () -> System.out.println("대출 불가"))
}

위와 같이 main 클래스 패스에 있는 클래스를 사용하여 LibraryService에 주입할 BookRepositoryImpl,  PushServiceImpl 클래스를 모두 하나의 파일에서 정의할 수 있다. 그리고, 준비된 클래스를 사용하여 LibraryService 객체를 생성할 있다.

 

Groovy Console에서 실행하면 아래와 같은 실행 결과를 확인할 있다.

위에서 구현한 인터페이스 2개가 모두 1개의 메서드만 가지고 있는 단일 추상 메서드(SAM, Single Abstract Method) 인터페이스이므로 람다로 대체할 수 있다. 우리는 REPL 사용하고 있으니 간결하게 수정할 있는지 바로 테스트해 있다.

 

아래 코드를 추가하고 실행한다.

println '--------------------------------------'
LibraryService libraryServiceUsingLambda = 
    new LibraryService(
        (String ignored) -> Optional<String>.of(
            new Book("1234", "Java Lambda", true)),
        (String message) -> println("pushed : $message"))
if (libraryServiceUsingLambda.isBookAvailable(isbn)) {
    libraryServiceUsingLambda.borrowBook(isbn)
            .ifPresentOrElse(title ->
            	System.out.println("대출 도서 : " + title),
                    () -> System.out.println("대출 불가"))
}

 

그러면, 아래와 같은 실행 결과를 확인할 있다.

 

이번에는 마지막으로 자바의 객체에 Lambda 대신 Groovy Closure 사용할 있는지 테스트해 보자.

println '--------------------------------------'
LibraryService libraryServiceUsingClosure = new LibraryService(
        { Optional<String>.of(
        	new Book("1234", "Groovy Closure", true)) },
        { println("pushed : $it") })
if (libraryServiceUsingClosure.isBookAvailable(isbn)) {
    libraryServiceUsingClosure.borrowBook(isbn)
            .ifPresentOrElse({ println("대출 도서 : " + it) },
                    { System.out.println("대출 불가") })
}

 

위의 코드는 자바의 Lambda를 사용한 부분을 Groovy의 Closure로 교체한 코드다.

실행해보면, 아래와 같이 모두 실행됨을 확인할 있다.

 

이제 Groovy Console 에 코드가 제법 많아졌다. 매번 실행할 때마다 현재 Groovy Console에 있는 코드를 모두 실행하지 않고 일부 코드만 바로 실행해 볼 필요가 있을 때도 많다.

이럴 때는 아래와 같이 실행하고자 하는 코드만 선택해서 실행할 있다.

 

코드 블록을 선택하고 실행해 보면 아래와 같이 LibraryService 객체가 생성되는 실행 결과를 확인할 있다.

 

하지만, 아래와 같이 코드를 선택하여 실행하면 안 된다.

 

현재 선택한 코드 블록에  isbn 변수 정의가 없기 때문에 에러가 발생한다. 

 

아래와 같이 isbn 변수를 정의해주면 IntelliJ 친절하게 이미 존재하는 변수라고 경고한다.

 

상태에서 코드 블록 선택 없이 콘솔 전체를 실행하면, 아래와 같이 경고받은 그대로 에러가 발생한다.

 

하지만, 아래와 같이 블록을 선택하고 실행하면 에러 없이 실행된다.

 

아래와 같이 선택한 코드 블록만 실행된 결과를 확인할 있다.

 

이런 식으로, 필요에 따라서 현재 콘솔에 입력된 코드 중에서 일부 코드 조각만 선택하여 실행하고 삭제하는 등 자유롭게 작업을 계속 진행할 수 있다.

 

이상으로 IntelliJ Groovy Console 대한 소개를 마치면서, 제 강의 쿠폰을 첨부합니다.

 

대규모 채팅 플랫폼으로 한 번에 끝내는 실전 대용량 트래픽 커버 완전판 | 패스트캠퍼스

전 카톡 서버 운영자가 알려주는 채팅 플랫폼 기반 '대용량' 트래픽 처리

fastcampus.co.kr

[FC 1위] 패스트캠퍼스 대용량 1위 기념! 강사 특별 할인 30% 쿠폰코드: PRDTEA250225_chat (~3/16)

 

반응형