sitelink1  
sitelink2  
sitelink3  
sitelink4  
sitelink5  
sitelink6  

javax.servlet.http.HttpServletjakarta.servlet.http.HttpServlet 중 어떤 패키지를 사용해야 할지 모르는 상황에서 코드 한 벌로 양쪽 WAS에서 동작하게 만들고 싶을 때, 현실적으로 가능한 방법은 다음과 같습니다:


✅ 해결 전략

???? 1. 빌드 타임에 결정 → 멀티 빌드 구조 사용

하나의 소스에서 빌드 시점에 어떤 WAS(또는 어떤 서블릿 API)를 대상으로 할지 결정하는 구조로 설계합니다.


???? 방법: Gradle의 sourceSet 또는 build variant 활용

???? 디렉토리 구조 예:

src/
  common/java/         ← 공통 로직
  javaee/java/         ← javax.servlet 기반 코드
  jakarta/java/        ← jakarta.servlet 기반 코드

???? build.gradle.kts 예:

val useJakarta = project.hasProperty("jakarta")

sourceSets {
    val main by getting {
        java {
            if (useJakarta) {
                setSrcDirs(listOf("src/common/java", "src/jakarta/java"))
            } else {
                setSrcDirs(listOf("src/common/java", "src/javaee/java"))
            }
        }
    }
}

dependencies {
    if (useJakarta) {
        implementation("jakarta.servlet:jakarta.servlet-api:5.0.0")
    } else {
        implementation("javax.servlet:javax.servlet-api:4.0.1")
    }
}

???? 실행 예:

# Java EE (javax.servlet) 빌드
./gradlew build

# Jakarta EE (jakarta.servlet) 빌드
./gradlew build -Pjakarta

???? 2. 동적 로딩 방식 (Class.forName + Reflection) [⚠️ 비추천]

Object servlet;
try {
    // 시도 1: jakarta.servlet
    Class<?> clazz = Class.forName("jakarta.servlet.http.HttpServlet");
    servlet = clazz.getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException e) {
    // 시도 2: javax.servlet
    Class<?> clazz = Class.forName("javax.servlet.http.HttpServlet");
    servlet = clazz.getDeclaredConstructor().newInstance();
}

그러나 extends HttpServlet 구문 자체는 컴파일 타임에 결정되므로, 실제 상속 구조를 동적으로 처리하는 건 불가능합니다. 위 방식은 서블릿 클래스를 감싸는 어댑터 객체 등에서 간접적으로 활용하는 형태에 한정됩니다.


???? 현실적으로는…

**"동일한 서블릿 클래스에서 두 패키지를 동시에 고려해 상속받는 것"**은 불가능합니다.

결국 컴파일 타임에 둘 중 하나를 선택하도록 구조를 만들고, WAS에 맞는 빌드를 수행하는 구조를 택하는 게 가장 현실적입니다.


 

 

 

javax.servlet.http.HttpServletjakarta.servlet.http.HttpServlet 둘 다 지원하기 위한 상속 분리 구조 예제를 아래에 설명드릴게요.


???? 목표

  • 공통 서블릿 로직은 중복 없이 유지하고,

  • 두 개의 WAS (Java EE, Jakarta EE) 모두에서 사용할 수 있도록

  • 각각 javax / jakarta 패키지에 맞는 클래스를 제공


???? 디렉토리 구조

src/
  main/
    java/
      common/                   ← 공통 서블릿 로직
        MyServletLogic.java
      javaee/                   ← javax.servlet 전용 클래스
        JavaxServletWrapper.java
      jakartaee/                ← jakarta.servlet 전용 클래스
        JakartaServletWrapper.java

???? 공통 서블릿 로직 클래스 (common/MyServletLogic.java)

package common;

import java.io.IOException;
import java.io.PrintWriter;

public class MyServletLogic {
    public void handleRequest(Object request, Object response) {
        try {
            Object writer = response.getClass().getMethod("getWriter").invoke(response);
            writer.getClass().getMethod("println", String.class).invoke(writer, "Hello from common logic!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

???? javax.servlet 기반 서블릿 (javaee/JavaxServletWrapper.java)

package javaee;

import common.MyServletLogic;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JavaxServletWrapper extends HttpServlet {
    private final MyServletLogic logic = new MyServletLogic();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        logic.handleRequest(req, resp);
    }
}

???? jakarta.servlet 기반 서블릿 (jakartaee/JakartaServletWrapper.java)

package jakartaee;

import common.MyServletLogic;

import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

public class JakartaServletWrapper extends HttpServlet {
    private final MyServletLogic logic = new MyServletLogic();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        logic.handleRequest(req, resp);
    }
}

???? Gradle 빌드 스크립트 예시 (build.gradle.kts)

val useJakarta = project.hasProperty("jakarta")

sourceSets["main"].java {
    setSrcDirs(
        listOf(
            "src/main/java/common",
            if (useJakarta) "src/main/java/jakartaee" else "src/main/java/javaee"
        )
    )
}

dependencies {
    if (useJakarta) {
        implementation("jakarta.servlet:jakarta.servlet-api:5.0.0")
    } else {
        implementation("javax.servlet:javax.servlet-api:4.0.1")
    }
}

빌드 명령

# javax.servlet 기반 빌드
./gradlew build

# jakarta.servlet 기반 빌드
./gradlew build -Pjakarta

✅ 요약

항목 설명
공통 로직 MyServletLogic 클래스에 유지
Wrapper 클래스 각각 JavaxServletWrapper, JakartaServletWrapper 로 나눔
유연한 빌드 Gradle 플래그에 따라 동적으로 패키지 선택 가능
장점 코드 중복 방지, 유지 보수 용이

 

 

 

 

GitHub 프로젝트 구조 예제를 아래와 같이 설계했습니다.

이 구조는 javax.servlet.http.HttpServletjakarta.servlet.http.HttpServlet 둘 다 사용할 수 있도록 상속 분리 방식으로 구성되어 있습니다:

dual-servlet-support/
├── build.gradle.kts
├── settings.gradle.kts
└── src/
    └── main/
        └── java/
            ├── common/
            │   └── MyServletLogic.java               // 실제 로직 구현
            ├── javaee/
            │   └── JavaxServletWrapper.java         // javax.servlet 기반 서블릿
            └── jakartaee/
                └── JakartaServletWrapper.java       // jakarta.servlet 기반 서블릿

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

번호 제목 글쓴이 날짜 조회 수
» [ChatGPT] javax.* 패키지와 jakarta.* 패키지의 혼합 사용 방안 황제낙엽 2025.04.15 27
62 [ChatGPT] *.servlet.http.HttpServlet 클래스를 사용할 수 있는 주요 WAS 목록 황제낙엽 2025.04.14 36
61 jakarta.servlet 패키지를 이용한 File Upload 구현 (2024.03.03, Servlet 5.0) 황제낙엽 2025.01.02 177
60 [ChatGPT] Java EE가 Jakarta EE로 전환 황제낙엽 2025.01.01 239
59 [ChatGPT] <jsp:include>에서 flush="true"를 설정시의 몇 가지 문제점 과 대안 황제낙엽 2024.07.19 208
58 [Copilot] JSP, Servlet, web.xml, mysql 한글 설정 황제낙엽 2024.07.12 179
57 Base64 클래스의 encode, decode 에서 URL-safe 황제낙엽 2024.07.10 273
56 [Copilot] JSP 에서 다른 페이지를 현재 페이지에 포함시키는 문법 (include) 황제낙엽 2024.06.26 224
55 [Gemini] HttpURLConnection 클래스를 이용한 데이터 전송 방식 비교 황제낙엽 2024.03.14 556
54 servlet name 에 camel case 를 사용해서는 안되는 이유 황제낙엽 2023.10.24 209
53 org.apache.commons.fileupload.servlet.ServletFileUpload 이용 예시 황제낙엽 2023.08.25 503
52 ServletFileUpload.parseRequest() 실행 결과 리스트가 비어있는 오류 황제낙엽 2023.08.25 659
51 어떤 multi-part 설정도 제공되지 않았기 때문에, part들을 처리할 수 없습니다. file 황제낙엽 2023.08.23 891
50 (Bard) the request was rejected because no multipart boundary was found file 황제낙엽 2023.08.23 337
49 (Bard) multipart/form-data 요청 처리를 위한 MultipartHttpServletRequest file 황제낙엽 2023.08.21 210
48 ajax 로 post 데이터를 servlet 으로 전달 받기 (with nexacro) [1] secret 황제낙엽 2023.02.26 0
47 HttpServletRequest, HttpServletResponse, JSONObject, POST 황제낙엽 2022.01.12 389
46 [JSP] 파일 다운로드 테스트 file 황제낙엽 2021.04.12 3560
45 [HttpURLConnection] Authorization 헤더를 넣어 GET Request 황제낙엽 2020.08.12 1062
44 [AWS, 웹 프로젝트] AWS+MySQL+SpringFrameWork5+JAVA8+ React+Gradle+Webpack+GIT+Jenkins file 황제낙엽 2020.04.08 553