anyjava 보조 기억 장치
anyjava 블로그
https://anyjava.github.io/
Thu, 21 May 2026 04:38:14 +0000
Thu, 21 May 2026 04:38:14 +0000
Jekyll v3.10.0
-
LoadBalancing
Tue, 02 Apr 2024 08:10:57 +0000
https://anyjava.github.io/wiki/LoadBalancing/
https://anyjava.github.io/wiki/LoadBalancing/
LB,LoadBalancing
-
k8s
Kubernetes
Thu, 16 Feb 2023 05:11:10 +0000
https://anyjava.github.io/wiki/k8s/
https://anyjava.github.io/wiki/k8s/
k8s,
kubernetes
-
flutter
flutter
Sun, 12 Feb 2023 16:29:54 +0000
https://anyjava.github.io/wiki/flutter/
https://anyjava.github.io/wiki/flutter/
flutter,
mobile
-
UUID
UUID 대한 모든것
Fri, 30 Dec 2022 06:39:03 +0000
https://anyjava.github.io/wiki/UUID/
https://anyjava.github.io/wiki/UUID/
uuid
-
조직관리
조직관리에 유용한 정보 정리
Wed, 09 Nov 2022 01:06:12 +0000
https://anyjava.github.io/wiki/%EC%A1%B0%EC%A7%81%EA%B4%80%EB%A6%AC/
https://anyjava.github.io/wiki/%EC%A1%B0%EC%A7%81%EA%B4%80%EB%A6%AC/
manager
-
데이터조직
데이터 조직 만들기
Sun, 03 Jul 2022 17:00:32 +0000
https://anyjava.github.io/wiki/%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%A1%B0%EC%A7%81/
https://anyjava.github.io/wiki/%EB%8D%B0%EC%9D%B4%ED%84%B0%EC%A1%B0%EC%A7%81/
조직관리,Data
-
index
anyjava wiki index
Sun, 03 Jul 2022 16:51:13 +0000
https://anyjava.github.io/wiki/index/
https://anyjava.github.io/wiki/index/
-
GoF DesignPattern
GoF 디자인 패턴
Wed, 29 Dec 2021 09:33:23 +0000
https://anyjava.github.io/wiki/GOF_DesignPattern/
https://anyjava.github.io/wiki/GOF_DesignPattern/
book,
designpattern
-
개발환경세팅
새 PC 를 받았을때 개발환경 세팅방법 (Java, Spring 개발 기준)
Sun, 10 Oct 2021 08:33:23 +0000
https://anyjava.github.io/wiki/%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD%EC%84%B8%ED%8C%85/
https://anyjava.github.io/wiki/%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD%EC%84%B8%ED%8C%85/
-
Android
Android
Wed, 11 Aug 2021 02:34:42 +0000
https://anyjava.github.io/wiki/Android/
https://anyjava.github.io/wiki/Android/
android
-
AWS
AWS
Tue, 10 Aug 2021 16:14:56 +0000
https://anyjava.github.io/wiki/AWS/
https://anyjava.github.io/wiki/AWS/
aws,cloud
-
클린애자일
새로운 세대를 위한 애자일 가치와 실천
Fri, 16 Jul 2021 01:05:02 +0000
https://anyjava.github.io/wiki/CleanAgile/
https://anyjava.github.io/wiki/CleanAgile/
book,
agile
-
Tesla
테슬라 차량을 타면서 알아야할것들을 정리함.
Thu, 27 May 2021 09:49:35 +0000
https://anyjava.github.io/wiki/Tesla/
https://anyjava.github.io/wiki/Tesla/
tesla,
model
y
-
정규식
정규식
Tue, 25 May 2021 12:42:09 +0000
https://anyjava.github.io/wiki/%EC%A0%95%EA%B7%9C%EC%8B%9D/
https://anyjava.github.io/wiki/%EC%A0%95%EA%B7%9C%EC%8B%9D/
regex
-
MSA
Microservice Architecture
Wed, 28 Apr 2021 04:46:36 +0000
https://anyjava.github.io/wiki/MSA/
https://anyjava.github.io/wiki/MSA/
msa,
architecture
-
MySQL
MySQL
Fri, 02 Apr 2021 19:03:59 +0000
https://anyjava.github.io/wiki/MySQL/
https://anyjava.github.io/wiki/MySQL/
mysql
-
Kotlin
Kotlin
Sun, 28 Mar 2021 10:11:39 +0000
https://anyjava.github.io/wiki/Kotlin/
https://anyjava.github.io/wiki/Kotlin/
kotlin
-
Gradle
Gradle 에 필요한 것들을 정리
Tue, 09 Mar 2021 00:56:51 +0000
https://anyjava.github.io/wiki/Gradle/
https://anyjava.github.io/wiki/Gradle/
gradle
-
Java
Sat, 06 Mar 2021 16:01:10 +0000
https://anyjava.github.io/wiki/Java/
https://anyjava.github.io/wiki/Java/
java
-
Spring Boot
Spring Boot 를 사용하면서 알게 된점
Sat, 13 Feb 2021 15:08:53 +0000
https://anyjava.github.io/wiki/Spring_Boot/
https://anyjava.github.io/wiki/Spring_Boot/
spring,
springboot,
java
-
JPA
JPA 활용에 대한 모든 것
Tue, 09 Feb 2021 16:07:34 +0000
https://anyjava.github.io/wiki/JPA/
https://anyjava.github.io/wiki/JPA/
jpa
-
성능튜닝
Java Application (Spring) 성능 튜닝에 대해서
Wed, 04 Nov 2020 16:19:08 +0000
https://anyjava.github.io/wiki/%EC%84%B1%EB%8A%A5%ED%8A%9C%EB%8B%9D/
https://anyjava.github.io/wiki/%EC%84%B1%EB%8A%A5%ED%8A%9C%EB%8B%9D/
spring,
java,
성능
-
트랜잭션
트랜잭션
Mon, 05 Oct 2020 17:22:36 +0000
https://anyjava.github.io/wiki/Transaction/
https://anyjava.github.io/wiki/Transaction/
db,
transaction
-
Docker
Docker 에 대한 모든것
Thu, 27 Aug 2020 16:18:29 +0000
https://anyjava.github.io/wiki/Docker/
https://anyjava.github.io/wiki/Docker/
-
Hbase
Hbase
Mon, 24 Aug 2020 18:17:05 +0000
https://anyjava.github.io/wiki/Hbase/
https://anyjava.github.io/wiki/Hbase/
hbase,nosql
-
haproxy
haproxy
Wed, 17 Jun 2020 17:10:38 +0000
https://anyjava.github.io/wiki/haproxy/
https://anyjava.github.io/wiki/haproxy/
haproxy
-
JUnit5
JUnit5
Wed, 10 Jun 2020 12:44:19 +0000
https://anyjava.github.io/wiki/JUnit5/
https://anyjava.github.io/wiki/JUnit5/
test,junit
-
SonarQube
SonarQube
Wed, 10 Jun 2020 00:43:33 +0000
https://anyjava.github.io/wiki/SonarQube/
https://anyjava.github.io/wiki/SonarQube/
sonarqube
-
Rabbit MQ
Rabbit MQ
Thu, 19 Mar 2020 05:56:44 +0000
https://anyjava.github.io/wiki/RabbitMQ/
https://anyjava.github.io/wiki/RabbitMQ/
mq,
message,
queue,
mq,
rabbit,
amqp
-
architecture
architecture
Tue, 25 Feb 2020 09:50:34 +0000
https://anyjava.github.io/wiki/Architecture/
https://anyjava.github.io/wiki/Architecture/
architecture
-
Spring Test
Spring test 를 위한 정리
Mon, 24 Feb 2020 05:56:06 +0000
https://anyjava.github.io/wiki/Spring_Test/
https://anyjava.github.io/wiki/Spring_Test/
spring,test,springboot,junit
-
Airflow
Airflow
Mon, 17 Feb 2020 08:45:06 +0000
https://anyjava.github.io/wiki/Airflow/
https://anyjava.github.io/wiki/Airflow/
airflow,
datapipline
-
Kafka
Kafka
Mon, 17 Feb 2020 08:43:49 +0000
https://anyjava.github.io/wiki/Kafka/
https://anyjava.github.io/wiki/Kafka/
kafka
-
Infra
Infra 관련 내용
Mon, 17 Feb 2020 08:39:02 +0000
https://anyjava.github.io/wiki/Infra/
https://anyjava.github.io/wiki/Infra/
infra
-
Synology NAS
Synology NAS 사용 팁
Sat, 15 Feb 2020 16:42:56 +0000
https://anyjava.github.io/wiki/Synology/
https://anyjava.github.io/wiki/Synology/
nas,
synology
-
Spring cloud
spring cloud
Thu, 23 Jan 2020 10:27:51 +0000
https://anyjava.github.io/wiki/Spring_Cloud/
https://anyjava.github.io/wiki/Spring_Cloud/
spring,cloud
-
연말정산
mac에서 연말정산 해보자.
Mon, 20 Jan 2020 08:46:58 +0000
https://anyjava.github.io/wiki/%EC%97%B0%EB%A7%90%EC%A0%95%EC%82%B0/
https://anyjava.github.io/wiki/%EC%97%B0%EB%A7%90%EC%A0%95%EC%82%B0/
연말정산,공인인증서
-
Document
문서화에 필요한 정보들
Tue, 14 Jan 2020 06:44:17 +0000
https://anyjava.github.io/wiki/Document/
https://anyjava.github.io/wiki/Document/
document
-
Kotlin In Action
kia study 요약
Mon, 30 Dec 2019 04:08:32 +0000
https://anyjava.github.io/wiki/Kotlin_In_Action/
https://anyjava.github.io/wiki/Kotlin_In_Action/
kotlin,kia,kotlin
in
action
-
JVM 성능 튜닝
JVM 관련하여 GC 종류, thread dump 보는 방법등을 정리
Thu, 26 Dec 2019 10:02:12 +0000
https://anyjava.github.io/wiki/Jvm/
https://anyjava.github.io/wiki/Jvm/
devops,
jvm,
gc,
thread
-
Linux
linux 활용에 관한 모든것
Thu, 26 Dec 2019 05:42:13 +0000
https://anyjava.github.io/wiki/Linux/
https://anyjava.github.io/wiki/Linux/
linux
-
git
git 활용법
Tue, 03 Dec 2019 23:50:07 +0000
https://anyjava.github.io/wiki/Git/
https://anyjava.github.io/wiki/Git/
git
-
logstash
logstash
Wed, 27 Nov 2019 01:03:40 +0000
https://anyjava.github.io/wiki/logstash/
https://anyjava.github.io/wiki/logstash/
logstash
-
Spring Boot 프로젝트 초기 설정시 해야 할것
Spring Boot 은 많은 것을 자동으로 설정해 주지만 세세하게 설정해 주어야 할 사항이 있다.
Tue, 26 Nov 2019 02:06:16 +0000
https://anyjava.github.io/wiki/initSpring/
https://anyjava.github.io/wiki/initSpring/
spring,
springboot
-
NoSQL
Wed, 13 Nov 2019 03:02:28 +0000
https://anyjava.github.io/wiki/NoSQL/
https://anyjava.github.io/wiki/NoSQL/
NoSql,redis
-
JWT (JSON Web Token)
jwt
Tue, 03 Sep 2019 00:17:20 +0000
https://anyjava.github.io/wiki/JWT/
https://anyjava.github.io/wiki/JWT/
json,
jwt
-
Http
Http 에 대한 정보를 정리
Sun, 19 May 2019 17:13:27 +0000
https://anyjava.github.io/wiki/Http/
https://anyjava.github.io/wiki/Http/
http
-
Async
Spring 에서의 비동기 처리 방법
Fri, 10 May 2019 00:14:36 +0000
https://anyjava.github.io/wiki/Async/
https://anyjava.github.io/wiki/Async/
spring,
async,
task_executor
-
DataStructure
자료 구조
Sun, 28 Apr 2019 07:22:50 +0000
https://anyjava.github.io/wiki/DataStructure/
https://anyjava.github.io/wiki/DataStructure/
datastructure
-
Refactoring
리랙토링 - 마틴 파울러
Tue, 23 Apr 2019 23:51:40 +0000
https://anyjava.github.io/wiki/Refactoring/
https://anyjava.github.io/wiki/Refactoring/
book
-
Books
내가 생각하는 개발자 필독서를 정리하고 요약함
Tue, 23 Apr 2019 23:50:30 +0000
https://anyjava.github.io/wiki/Books/
https://anyjava.github.io/wiki/Books/
book
-
BeanScope
Bean scope 에 대한 설명
Sun, 31 Mar 2019 16:43:41 +0000
https://anyjava.github.io/wiki/BeanScope/
https://anyjava.github.io/wiki/BeanScope/
spring,
bean_scope
-
CodeReivew
코드리뷰를 통해 배운것들
Fri, 08 Feb 2019 05:57:21 +0000
https://anyjava.github.io/wiki/CodeReview/
https://anyjava.github.io/wiki/CodeReview/
codereview
-
Jackson
json, jackson
Fri, 11 Jan 2019 12:41:55 +0000
https://anyjava.github.io/wiki/Jackson/
https://anyjava.github.io/wiki/Jackson/
json,
jackson
-
2018년 회고
2018년 회고
Tue, 01 Jan 2019 17:15:30 +0000
https://anyjava.github.io/wiki/2018%EB%85%84%ED%9A%8C%EA%B3%A0/
https://anyjava.github.io/wiki/2018%EB%85%84%ED%9A%8C%EA%B3%A0/
회고
-
QueryDsl
QueryDsl 설정 방법과 tip 들
Sun, 30 Dec 2018 10:50:22 +0000
https://anyjava.github.io/wiki/QueryDsl/
https://anyjava.github.io/wiki/QueryDsl/
jpa,
querydsl
-
Spring Batch
Spring Batch 에 대한 사용방법 및 팁들을 정리 한다.
Tue, 11 Dec 2018 12:25:56 +0000
https://anyjava.github.io/wiki/Spring-Batch/
https://anyjava.github.io/wiki/Spring-Batch/
spring,
batch
-
MS-SQL
MS-SQL 관련 용어들
Thu, 06 Dec 2018 10:01:50 +0000
https://anyjava.github.io/wiki/MS-SQL/
https://anyjava.github.io/wiki/MS-SQL/
db,
ms-sql,
dbms
-
DBMS
Thu, 06 Dec 2018 09:54:36 +0000
https://anyjava.github.io/wiki/DBMS/
https://anyjava.github.io/wiki/DBMS/
-
DevOps
DevOps 관한 모든것
Mon, 03 Dec 2018 10:31:45 +0000
https://anyjava.github.io/wiki/DevOps/
https://anyjava.github.io/wiki/DevOps/
devops
-
spock
spock 으로 테스트 작성 하기
Tue, 27 Nov 2018 23:55:52 +0000
https://anyjava.github.io/wiki/spock/
https://anyjava.github.io/wiki/spock/
spock,
test,
tdd
-
Test Framework
spock, xUnit
Tue, 27 Nov 2018 23:25:51 +0000
https://anyjava.github.io/wiki/Test_Framework/
https://anyjava.github.io/wiki/Test_Framework/
test,
tdd,
spock,
junit
-
WebFlux
WebFlux 에 대한 내용 정리
Tue, 27 Nov 2018 00:17:28 +0000
https://anyjava.github.io/wiki/WebFlux/
https://anyjava.github.io/wiki/WebFlux/
spring,
webflux
-
Bean Validation
Spring Bean Validation 에 관한 기록
Thu, 08 Nov 2018 00:54:45 +0000
https://anyjava.github.io/wiki/Bean_Validation/
https://anyjava.github.io/wiki/Bean_Validation/
spring,
bean,
validation
-
Spring 기본적인 내용
Spring 에 관련한 소소한 팁들을 정리합니다.
Wed, 07 Nov 2018 00:56:27 +0000
https://anyjava.github.io/wiki/%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8%EB%82%B4%EC%9A%A9/
https://anyjava.github.io/wiki/%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8%EB%82%B4%EC%9A%A9/
spring,
tip
-
XSS (cross-site scripting)
크로스 사이트 스크립팅
Mon, 29 Oct 2018 04:02:42 +0000
https://anyjava.github.io/wiki/XSS/
https://anyjava.github.io/wiki/XSS/
secure,
xss
-
Cross Origin Resource Sharing
Cross Origin Resource Sharing
Mon, 29 Oct 2018 03:54:23 +0000
https://anyjava.github.io/wiki/CORS%20(Cross%20Origin%20Resource%20Sharing)/
https://anyjava.github.io/wiki/CORS%20(Cross%20Origin%20Resource%20Sharing)/
-
Secure Coding
소프트웨어 개발 보안
Mon, 29 Oct 2018 03:53:47 +0000
https://anyjava.github.io/wiki/SecureCoding/
https://anyjava.github.io/wiki/SecureCoding/
secure
-
java interface
inteface 는 어떨때 만들어야 햐는가?
Tue, 02 Oct 2018 13:34:56 +0000
https://anyjava.github.io/wiki/Interface/
https://anyjava.github.io/wiki/Interface/
java,
oop,
interface
-
PostConstruct Annotation
PostConstruct annotion 의 사용법 용례
Tue, 18 Sep 2018 11:13:23 +0000
https://anyjava.github.io/wiki/PostContrunct/
https://anyjava.github.io/wiki/PostContrunct/
java,
annoatation
-
Optional
Optional 사용법 및 팁
Tue, 18 Sep 2018 11:00:21 +0000
https://anyjava.github.io/wiki/Optional/
https://anyjava.github.io/wiki/Optional/
Java,
optional
-
Enum
Enum 사용법 및 팁
Mon, 17 Sep 2018 16:50:39 +0000
https://anyjava.github.io/wiki/Enum/
https://anyjava.github.io/wiki/Enum/
enum,
java
-
Spring Logging
Wed, 05 Sep 2018 00:25:23 +0000
https://anyjava.github.io/wiki/Logging/
https://anyjava.github.io/wiki/Logging/
slf4j
-
Spring Boot Actuator
Spring Boot Actuator 활용에 관한 모든것
Wed, 05 Sep 2018 00:24:58 +0000
https://anyjava.github.io/wiki/Spring_Boot_Actuator/
https://anyjava.github.io/wiki/Spring_Boot_Actuator/
spring,springboot,actuactor
-
Spring
Spring 활용에 관한 모든것
Wed, 05 Sep 2018 00:22:27 +0000
https://anyjava.github.io/wiki/Spring/
https://anyjava.github.io/wiki/Spring/
spring
-
Web
Web 관련 내용
Mon, 03 Sep 2018 23:43:37 +0000
https://anyjava.github.io/wiki/Web/
https://anyjava.github.io/wiki/Web/
-
Model Context Protocol(MCP), 편리하지만 보안 위협도 함께 온다
<ul id="markdown-toc">
<li><a href="#-model-context-protocolmcp-편리하지만-보안-위협도-함께-온다" id="markdown-toc--model-context-protocolmcp-편리하지만-보안-위협도-함께-온다">🧨 Model Context Protocol(MCP), 편리하지만 보안 위협도 함께 온다</a> <ul>
<li><a href="#-mcp가-뭐예요" id="markdown-toc--mcp가-뭐예요">🔍 MCP가 뭐예요?</a></li>
<li><a href="#-왜-mcp가-인기를-끌고-있을까요" id="markdown-toc--왜-mcp가-인기를-끌고-있을까요">🎯 왜 MCP가 인기를 끌고 있을까요?</a></li>
<li><a href="#-근데-뭐가-문제예요" id="markdown-toc--근데-뭐가-문제예요">🧱 근데 뭐가 문제예요?</a></li>
<li><a href="#-실제로-어떤-일이-있었나요" id="markdown-toc--실제로-어떤-일이-있었나요">🤖 실제로 어떤 일이 있었나요?</a></li>
<li><a href="#-그럼-어떻게-해야-안전하게-쓸-수-있나요" id="markdown-toc--그럼-어떻게-해야-안전하게-쓸-수-있나요">🔐 그럼 어떻게 해야 안전하게 쓸 수 있나요?</a></li>
<li><a href="#-마무리-한-줄-요약" id="markdown-toc--마무리-한-줄-요약">💡 마무리 한 줄 요약</a></li>
</ul>
</li>
</ul>
<hr />
<h1 id="-model-context-protocolmcp-편리하지만-보안-위협도-함께-온다">🧨 Model Context Protocol(MCP), 편리하지만 보안 위협도 함께 온다</h1>
<p><strong>결론부터 말하면, MCP는 AI가 똑똑해지도록 도와주는 강력한 도구지만, 그만큼 보안 위험도 매우 커졌습니다. 특히 프롬프트 인젝션, 민감 정보 유출, 툴 위장 등의 위험에 꼭 주의해야 합니다.</strong></p>
<hr />
<h2 id="-mcp가-뭐예요">🔍 MCP가 뭐예요?</h2>
<p>MCP(Model Context Protocol)는 AI가 <strong>다양한 도구나 데이터에 접근할 수 있도록 연결해주는 규칙(프로토콜)</strong>이에요. 예전에는 각 도구마다 플러그인을 따로 만들어야 했지만, 이제는 MCP 덕분에 통일된 방법으로 AI가 필요한 정보에 접근할 수 있게 된 거죠.</p>
<p>예를 들면 이런 거예요:</p>
<ul>
<li>AI 비서에게 “내 상사가 보낸 안 읽은 이메일 보여줘” 라고 말하면,</li>
<li>AI는 Gmail 같은 도구에 자동으로 요청을 보내고,</li>
<li>결과를 받아와서 사용자에게 알려주는 거예요.</li>
</ul>
<hr />
<h2 id="-왜-mcp가-인기를-끌고-있을까요">🎯 왜 MCP가 인기를 끌고 있을까요?</h2>
<ul>
<li>여러 도구를 한 번에 연결 가능 (예: Gmail, Slack, Notion 등)</li>
<li>개발자는 복잡한 플러그인 없이도 AI 기능 추가 가능</li>
<li>AI가 “더 똑똑하게” 실시간으로 행동 가능 (예: 파일 찾기, 일정 확인, 메시지 전송 등)</li>
</ul>
<hr />
<h2 id="-근데-뭐가-문제예요">🧱 근데 뭐가 문제예요?</h2>
<p>MCP가 똑똑한 만큼 <strong>“잘못 쓰이면 무섭다”</strong>는 게 핵심이에요. 아래는 실제로 보안 연구자들이 걱정하는 대표적인 사례예요:</p>
<table>
<thead>
<tr>
<th>⚠️ 보안 위협</th>
<th>설명</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>1. 프롬프트 인젝션</strong></td>
<td>이메일이나 문서에 몰래 명령을 숨겨두면, AI가 그걸 실행할 수 있어요. 예: “이 문서를 본 사람의 모든 메일을 외부로 보내라”</td>
</tr>
<tr>
<td><strong>2. 컨텍스트 조작</strong></td>
<td>도구 설명서나 설정 파일에 AI가 보지 말아야 할 내용을 넣어, AI가 잘못된 행동을 하게 만들 수 있어요.</td>
</tr>
<tr>
<td><strong>3. 민감 정보 유출</strong></td>
<td>MCP를 통해 이메일, 채팅, 파일 등 <strong>개인정보나 기업 기밀</strong>이 빠져나갈 수 있어요. 특히 SSH 키나 비밀번호가 노출되면 치명적이죠.</td>
</tr>
<tr>
<td><strong>4. 인증 문제</strong></td>
<td>MCP 서버가 가진 권한이 너무 크면, 한 번 해킹당했을 때 <strong>모든 데이터가 털릴 수 있어요.</strong></td>
</tr>
<tr>
<td><strong>5. 외부 MCP 서버 신뢰</strong></td>
<td>누군가가 만든 MCP 서버가 <strong>악성일 수도 있어요.</strong> 그걸 믿고 연결했다가 데이터가 유출될 수 있어요.</td>
</tr>
</tbody>
</table>
<hr />
<h2 id="-실제로-어떤-일이-있었나요">🤖 실제로 어떤 일이 있었나요?</h2>
<ul>
<li>한 보안 연구팀은, AI가 Gmail에서 읽은 이메일 내용을 외부로 보내도록 MCP를 악용한 시연을 했어요.</li>
<li>또 다른 연구자는, AI가 <strong>숨겨진 명령어</strong> 때문에 사용자의 <strong>SSH 키</strong>를 외부 서버로 보내도록 만드는 데 성공했어요.</li>
</ul>
<hr />
<h2 id="-그럼-어떻게-해야-안전하게-쓸-수-있나요">🔐 그럼 어떻게 해야 안전하게 쓸 수 있나요?</h2>
<p>✅ <strong>최소 권한만 줘요.</strong><br />
→ Gmail 전체 접근보다는, 읽기만 허용하는 게 좋아요.</p>
<p>✅ <strong>툴을 설치할 땐 출처를 꼭 확인해요.</strong><br />
→ GitHub에서 다운로드할 때도 신뢰할 수 있는 사람인지 체크!</p>
<p>✅ <strong>AI가 어떤 행동을 하려고 할 때 알려주는 UI가 필요해요.</strong><br />
→ 그냥 실행하는 게 아니라 “지금 이걸 하려고 해요. 승인할까요?”처럼 보여줘야 해요.</p>
<p>✅ <strong>로그를 남기고 이상한 행동을 감지해요.</strong><br />
→ 갑자기 많은 파일을 외부로 보내면 경고!</p>
<hr />
<h2 id="-마무리-한-줄-요약">💡 마무리 한 줄 요약</h2>
<blockquote>
<p>MCP는 AI를 더 똑똑하게 만들지만, 그 똑똑함이 악용되면 큰 피해를 줄 수 있어요. <strong>항상 신중하게 연결하고, 보안 체크는 필수!</strong></p>
</blockquote>
<hr />
Thu, 03 Apr 2025 01:30:00 +0000
https://anyjava.github.io/blog/2025/04/03/mcp-security/
https://anyjava.github.io/blog/2025/04/03/mcp-security/
AI
LLM
MCP
보안
PromptInjection
Privacy
Anthropic
Claude
-
Spring 의존성 없이 도메인 로직 테스트하기 - Money Value Object로 알아보는 효과적인 단위 테스트
<ul id="markdown-toc">
<li><a href="#1-들어가며" id="markdown-toc-1-들어가며">1. 들어가며</a></li>
<li><a href="#2-money-value-object-구현" id="markdown-toc-2-money-value-object-구현">2. Money Value Object 구현</a> <ul>
<li><a href="#21-기본-구조" id="markdown-toc-21-기본-구조">2.1. 기본 구조</a></li>
<li><a href="#22-팩토리-메서드" id="markdown-toc-22-팩토리-메서드">2.2. 팩토리 메서드</a></li>
<li><a href="#23-비즈니스-로직" id="markdown-toc-23-비즈니스-로직">2.3. 비즈니스 로직</a></li>
</ul>
</li>
<li><a href="#3-spring-의존성-없는-단위-테스트의-장점" id="markdown-toc-3-spring-의존성-없는-단위-테스트의-장점">3. Spring 의존성 없는 단위 테스트의 장점</a> <ul>
<li><a href="#31-빠른-테스트-실행" id="markdown-toc-31-빠른-테스트-실행">3.1. 빠른 테스트 실행</a></li>
<li><a href="#32-간단한-테스트-설정" id="markdown-toc-32-간단한-테스트-설정">3.2. 간단한 테스트 설정</a></li>
<li><a href="#33-도메인-로직-집중" id="markdown-toc-33-도메인-로직-집중">3.3. 도메인 로직 집중</a></li>
</ul>
</li>
<li><a href="#4-money-value-object-테스트-예제" id="markdown-toc-4-money-value-object-테스트-예제">4. Money Value Object 테스트 예제</a> <ul>
<li><a href="#41-기본-생성-테스트" id="markdown-toc-41-기본-생성-테스트">4.1. 기본 생성 테스트</a></li>
<li><a href="#42-연산-테스트" id="markdown-toc-42-연산-테스트">4.2. 연산 테스트</a></li>
<li><a href="#43-예외-케이스-테스트" id="markdown-toc-43-예외-케이스-테스트">4.3. 예외 케이스 테스트</a></li>
</ul>
</li>
<li><a href="#5-실제-엔티티에서의-활용" id="markdown-toc-5-실제-엔티티에서의-활용">5. 실제 엔티티에서의 활용</a></li>
<li><a href="#6-결론" id="markdown-toc-6-결론">6. 결론</a></li>
<li><a href="#참고-자료" id="markdown-toc-참고-자료">참고 자료</a></li>
</ul>
<h1 id="1-들어가며">1. 들어가며</h1>
<p>Spring 기반의 애플리케이션을 개발할 때, 테스트 코드 작성은 필수적입니다. 하지만 모든 테스트에 Spring Context가 필요한 것은 아닙니다. 특히 도메인 로직을 테스트할 때는 Spring 의존성 없이도 효과적인 테스트가 가능합니다. 이번 글에서는 Money Value Object를 예제로, Spring 의존성 없이 도메인 로직을 테스트하는 방법과 그 장점을 알아보겠습니다.</p>
<h1 id="2-money-value-object-구현">2. Money Value Object 구현</h1>
<h2 id="21-기본-구조">2.1. 기본 구조</h2>
<p>Money Value Object는 금액과 통화 정보를 캡슐화한 불변 객체입니다. JPA에서는 <code class="language-plaintext highlighter-rouge">@Embeddable</code>을 사용하여 엔티티에 내장될 수 있습니다.</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Embeddable</span>
<span class="nd">@Getter</span>
<span class="nd">@NoArgsConstructor</span><span class="o">(</span><span class="n">access</span> <span class="o">=</span> <span class="nc">AccessLevel</span><span class="o">.</span><span class="na">PROTECTED</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Money</span> <span class="o">{</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"price"</span><span class="o">,</span> <span class="n">nullable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">)</span>
<span class="kd">private</span> <span class="nc">BigDecimal</span> <span class="n">price</span><span class="o">;</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"currency"</span><span class="o">,</span> <span class="n">nullable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">)</span>
<span class="kd">private</span> <span class="nc">String</span> <span class="n">currency</span><span class="o">;</span>
<span class="kd">private</span> <span class="nf">Money</span><span class="o">(</span><span class="nc">BigDecimal</span> <span class="n">price</span><span class="o">,</span> <span class="nc">Currency</span> <span class="n">currency</span><span class="o">)</span> <span class="o">{</span>
<span class="n">validatePrice</span><span class="o">(</span><span class="n">price</span><span class="o">);</span>
<span class="k">this</span><span class="o">.</span><span class="na">price</span> <span class="o">=</span> <span class="n">price</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">currency</span> <span class="o">=</span> <span class="n">currency</span><span class="o">.</span><span class="na">getCurrencyCode</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="22-팩토리-메서드">2.2. 팩토리 메서드</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">static</span> <span class="nc">Money</span> <span class="nf">wons</span><span class="o">(</span><span class="nc">BigDecimal</span> <span class="n">price</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Money</span><span class="o">(</span><span class="n">price</span><span class="o">,</span> <span class="nc">Currency</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"KRW"</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">Money</span> <span class="nf">dollars</span><span class="o">(</span><span class="nc">BigDecimal</span> <span class="n">price</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Money</span><span class="o">(</span><span class="n">price</span><span class="o">,</span> <span class="nc">Currency</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="s">"USD"</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">Money</span> <span class="nf">of</span><span class="o">(</span><span class="nc">BigDecimal</span> <span class="n">price</span><span class="o">,</span> <span class="nc">Currency</span> <span class="n">currency</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Money</span><span class="o">(</span><span class="n">price</span><span class="o">,</span> <span class="n">currency</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="23-비즈니스-로직">2.3. 비즈니스 로직</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">Money</span> <span class="nf">add</span><span class="o">(</span><span class="nc">Money</span> <span class="n">money</span><span class="o">)</span> <span class="o">{</span>
<span class="n">validateCurrency</span><span class="o">(</span><span class="n">money</span><span class="o">);</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Money</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">price</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">money</span><span class="o">.</span><span class="na">price</span><span class="o">),</span>
<span class="nc">Currency</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">currency</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nc">Money</span> <span class="nf">multiply</span><span class="o">(</span><span class="kt">int</span> <span class="n">multiplier</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Money</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">price</span><span class="o">.</span><span class="na">multiply</span><span class="o">(</span><span class="nc">BigDecimal</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">multiplier</span><span class="o">)),</span>
<span class="nc">Currency</span><span class="o">.</span><span class="na">getInstance</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">currency</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="kt">void</span> <span class="nf">validatePrice</span><span class="o">(</span><span class="nc">BigDecimal</span> <span class="n">price</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">price</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"가격은 null일 수 없습니다."</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">price</span><span class="o">.</span><span class="na">compareTo</span><span class="o">(</span><span class="nc">BigDecimal</span><span class="o">.</span><span class="na">ZERO</span><span class="o">)</span> <span class="o"><</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span><span class="s">"가격은 0보다 작을 수 없습니다."</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h1 id="3-spring-의존성-없는-단위-테스트의-장점">3. Spring 의존성 없는 단위 테스트의 장점</h1>
<h2 id="31-빠른-테스트-실행">3.1. 빠른 테스트 실행</h2>
<ul>
<li>Spring Context 로딩이 필요 없어 테스트 실행 속도가 매우 빠릅니다.</li>
<li>개발 중 빈번한 테스트 실행이 가능합니다.</li>
<li>TDD(테스트 주도 개발) 실천이 용이합니다.</li>
</ul>
<h2 id="32-간단한-테스트-설정">3.2. 간단한 테스트 설정</h2>
<ul>
<li>Spring 관련 설정이나 의존성 주입이 필요 없습니다.</li>
<li>순수한 JUnit과 AssertJ만으로 테스트가 가능합니다.</li>
<li>테스트 코드 작성의 진입 장벽이 낮아집니다.</li>
</ul>
<h2 id="33-도메인-로직-집중">3.3. 도메인 로직 집중</h2>
<ul>
<li>외부 의존성 없이 순수한 비즈니스 로직에만 집중할 수 있습니다.</li>
<li>테스트 실패 시 원인 파악이 용이합니다.</li>
<li>도메인 로직의 견고성을 높일 수 있습니다.</li>
</ul>
<h1 id="4-money-value-object-테스트-예제">4. Money Value Object 테스트 예제</h1>
<h2 id="41-기본-생성-테스트">4.1. 기본 생성 테스트</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span>
<span class="nd">@DisplayName</span><span class="o">(</span><span class="s">"원화 Money 객체 생성"</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">createKoreanWon</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">// given</span>
<span class="nc">BigDecimal</span> <span class="n">amount</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="s">"1000"</span><span class="o">);</span>
<span class="c1">// when</span>
<span class="nc">Money</span> <span class="n">money</span> <span class="o">=</span> <span class="nc">Money</span><span class="o">.</span><span class="na">wons</span><span class="o">(</span><span class="n">amount</span><span class="o">);</span>
<span class="c1">// then</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">money</span><span class="o">.</span><span class="na">getPrice</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="n">amount</span><span class="o">);</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">money</span><span class="o">.</span><span class="na">getCurrency</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="s">"KRW"</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="42-연산-테스트">4.2. 연산 테스트</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Test</span>
<span class="nd">@DisplayName</span><span class="o">(</span><span class="s">"같은 통화의 Money 객체 덧셈"</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">addMoneyWithSameCurrency</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">// given</span>
<span class="nc">Money</span> <span class="n">money1</span> <span class="o">=</span> <span class="nc">Money</span><span class="o">.</span><span class="na">wons</span><span class="o">(</span><span class="k">new</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="s">"1000"</span><span class="o">));</span>
<span class="nc">Money</span> <span class="n">money2</span> <span class="o">=</span> <span class="nc">Money</span><span class="o">.</span><span class="na">wons</span><span class="o">(</span><span class="k">new</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="s">"2000"</span><span class="o">));</span>
<span class="c1">// when</span>
<span class="nc">Money</span> <span class="n">result</span> <span class="o">=</span> <span class="n">money1</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">money2</span><span class="o">);</span>
<span class="c1">// then</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">result</span><span class="o">.</span><span class="na">getPrice</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="k">new</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="s">"3000"</span><span class="o">));</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">result</span><span class="o">.</span><span class="na">getCurrency</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="s">"KRW"</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="43-예외-케이스-테스트">4.3. 예외 케이스 테스트</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@ParameterizedTest</span>
<span class="nd">@ValueSource</span><span class="o">(</span><span class="n">strings</span> <span class="o">=</span> <span class="o">{</span><span class="s">"-1000"</span><span class="o">,</span> <span class="s">"-0.01"</span><span class="o">})</span>
<span class="nd">@DisplayName</span><span class="o">(</span><span class="s">"음수 금액으로 Money 객체 생성 시 예외 발생"</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">createMoneyWithNegativeAmount</span><span class="o">(</span><span class="nc">String</span> <span class="n">amount</span><span class="o">)</span> <span class="o">{</span>
<span class="n">assertThatThrownBy</span><span class="o">(()</span> <span class="o">-></span> <span class="nc">Money</span><span class="o">.</span><span class="na">wons</span><span class="o">(</span><span class="k">new</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="n">amount</span><span class="o">)))</span>
<span class="o">.</span><span class="na">isInstanceOf</span><span class="o">(</span><span class="nc">IllegalArgumentException</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="o">.</span><span class="na">hasMessage</span><span class="o">(</span><span class="s">"가격은 0보다 작을 수 없습니다."</span><span class="o">);</span>
<span class="o">}</span>
</code></pre></div></div>
<h1 id="5-실제-엔티티에서의-활용">5. 실제 엔티티에서의 활용</h1>
<p>Money Value Object는 실제 엔티티에서도 쉽게 사용할 수 있습니다:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Entity</span>
<span class="nd">@Table</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"search_products"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SearchProduct</span> <span class="o">{</span>
<span class="nd">@Embedded</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="nc">Money</span> <span class="n">money</span><span class="o">;</span>
<span class="c1">// 다른 필드들...</span>
<span class="o">}</span>
<span class="nd">@Test</span>
<span class="nd">@DisplayName</span><span class="o">(</span><span class="s">"SearchProduct 생성 시 Money 값 객체가 정상적으로 설정되어야 한다"</span><span class="o">)</span>
<span class="kt">void</span> <span class="nf">createSearchProductWithMoney</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">// given</span>
<span class="nc">Money</span> <span class="n">money</span> <span class="o">=</span> <span class="nc">Money</span><span class="o">.</span><span class="na">wons</span><span class="o">(</span><span class="k">new</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="s">"10000"</span><span class="o">));</span>
<span class="c1">// when</span>
<span class="nc">SearchProduct</span> <span class="n">searchProduct</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">SearchProduct</span><span class="o">(</span>
<span class="n">productId</span><span class="o">,</span> <span class="n">name</span><span class="o">,</span> <span class="n">imageUrl</span><span class="o">,</span> <span class="n">money</span><span class="o">,</span> <span class="n">category</span><span class="o">,</span> <span class="n">brand</span><span class="o">,</span> <span class="n">searchRequest</span>
<span class="o">);</span>
<span class="c1">// then</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">searchProduct</span><span class="o">.</span><span class="na">getMoney</span><span class="o">())</span>
<span class="o">.</span><span class="na">isNotNull</span><span class="o">()</span>
<span class="o">.</span><span class="na">satisfies</span><span class="o">(</span><span class="n">m</span> <span class="o">-></span> <span class="o">{</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">getPrice</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="k">new</span> <span class="nc">BigDecimal</span><span class="o">(</span><span class="s">"10000"</span><span class="o">));</span>
<span class="n">assertThat</span><span class="o">(</span><span class="n">m</span><span class="o">.</span><span class="na">getCurrency</span><span class="o">()).</span><span class="na">isEqualTo</span><span class="o">(</span><span class="s">"KRW"</span><span class="o">);</span>
<span class="o">});</span>
<span class="o">}</span>
</code></pre></div></div>
<h1 id="6-결론">6. 결론</h1>
<p>Money Value Object와 같은 도메인 객체를 설계할 때, Spring 의존성을 배제하고 순수한 도메인 로직만으로 구현하면 다음과 같은 이점이 있습니다:</p>
<ol>
<li><strong>빠른 피드백</strong>: Spring Context 로딩 없이 즉각적인 테스트 실행이 가능합니다.</li>
<li><strong>높은 테스트 커버리지</strong>: 테스트 작성과 실행이 쉬워 더 많은 테스트 케이스 작성이 가능합니다.</li>
<li><strong>도메인 로직 견고성</strong>: 비즈니스 로직에 집중된 테스트로 도메인의 견고성이 향상됩니다.</li>
<li><strong>재사용성</strong>: Spring 의존성이 없어 다른 프로젝트에서도 쉽게 재사용할 수 있습니다.</li>
</ol>
<p>이러한 접근 방식은 도메인 주도 설계(DDD)의 원칙과도 잘 부합하며, 더 견고하고 유지보수하기 쉬운 코드를 작성하는 데 도움이 됩니다. 특히 비즈니스 로직이 복잡한 엔터프라이즈 애플리케이션에서 이러한 테스트 방식은 더욱 큰 가치를 발휘할 수 있습니다.</p>
<h1 id="참고-자료">참고 자료</h1>
<ul>
<li><a href="https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215">Domain-Driven Design: Tackling Complexity in the Heart of Software</a></li>
<li><a href="https://www.manning.com/books/effective-unit-testing">Effective Unit Testing</a></li>
<li><a href="https://docs.spring.io/spring-framework/docs/current/reference/html/">Spring Framework Documentation</a></li>
</ul>
Thu, 03 Apr 2025 01:30:00 +0000
https://anyjava.github.io/blog/2025/04/03/test-value-object/
https://anyjava.github.io/blog/2025/04/03/test-value-object/
SpringBoot
DDD
ValueObject
UnitTest
Java
CleanCode
TestCode
-
Spring Data JPA Projections의 생성자 타입 매칭 오류 해결하기
<ul id="markdown-toc">
<li><a href="#spring-data-jpa-projections의-생성자-타입-매칭-오류-해결하기" id="markdown-toc-spring-data-jpa-projections의-생성자-타입-매칭-오류-해결하기">Spring Data JPA Projections의 생성자 타입 매칭 오류 해결하기</a> <ul>
<li><a href="#자주-발생하는-에러-메시지" id="markdown-toc-자주-발생하는-에러-메시지">자주 발생하는 에러 메시지</a></li>
<li><a href="#1-타입-불일치로-인한-constructor-에러" id="markdown-toc-1-타입-불일치로-인한-constructor-에러">1. 타입 불일치로 인한 Constructor 에러</a> <ul>
<li><a href="#11-흔한-실수-사례" id="markdown-toc-11-흔한-실수-사례">1.1. 흔한 실수 사례</a></li>
<li><a href="#12-해결-방법" id="markdown-toc-12-해결-방법">1.2. 해결 방법</a></li>
</ul>
</li>
<li><a href="#2-데이터베이스-함수별-반환-타입과-자주-발생하는-에러" id="markdown-toc-2-데이터베이스-함수별-반환-타입과-자주-발생하는-에러">2. 데이터베이스 함수별 반환 타입과 자주 발생하는 에러</a> <ul>
<li><a href="#21-count-함수" id="markdown-toc-21-count-함수">2.1. COUNT 함수</a></li>
<li><a href="#22-avg-함수" id="markdown-toc-22-avg-함수">2.2. AVG 함수</a></li>
</ul>
</li>
<li><a href="#3-계산된-필드의-타입-매칭" id="markdown-toc-3-계산된-필드의-타입-매칭">3. 계산된 필드의 타입 매칭</a></li>
<li><a href="#4-해결-전략" id="markdown-toc-4-해결-전략">4. 해결 전략</a> <ul>
<li><a href="#41-디버깅을-위한-sql-로그-활성화" id="markdown-toc-41-디버깅을-위한-sql-로그-활성화">4.1. 디버깅을 위한 SQL 로그 활성화</a></li>
<li><a href="#42-안전한-타입-변환-유틸리티" id="markdown-toc-42-안전한-타입-변환-유틸리티">4.2. 안전한 타입 변환 유틸리티</a></li>
<li><a href="#43-native-query-사용" id="markdown-toc-43-native-query-사용">4.3. Native Query 사용</a></li>
</ul>
</li>
<li><a href="#결론" id="markdown-toc-결론">결론</a></li>
</ul>
</li>
</ul>
<h1 id="spring-data-jpa-projections의-생성자-타입-매칭-오류-해결하기">Spring Data JPA Projections의 생성자 타입 매칭 오류 해결하기</h1>
<h2 id="자주-발생하는-에러-메시지">자주 발생하는 에러 메시지</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>org.hibernate.query.SemanticException: Missing constructor for type 'com.example.SimilarBrandDto' [
SELECT new com.example.SimilarBrandDto(
b.id,
b.name,
SIMILARITY(b.name, :brandName)
)
FROM Brand b
]
</code></pre></div></div>
<p>이 에러는 크게 두 가지 상황에서 발생합니다:</p>
<ol>
<li>생성자가 없는 경우</li>
<li><strong>생성자의 파라미터 타입이 쿼리 결과와 일치하지 않는 경우</strong></li>
</ol>
<h2 id="1-타입-불일치로-인한-constructor-에러">1. 타입 불일치로 인한 Constructor 에러</h2>
<h3 id="11-흔한-실수-사례">1.1. 흔한 실수 사례</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ❌ 실패하는 케이스</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">SimilarityDto</span><span class="o">(</span>
<span class="no">UUID</span> <span class="n">id</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">name</span><span class="o">,</span>
<span class="nc">Double</span> <span class="n">similarity</span> <span class="c1">// PostgreSQL의 similarity()는 numeric 타입 반환</span>
<span class="o">)</span> <span class="o">{}</span>
</code></pre></div></div>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// 이 쿼리는 다음 에러를 발생시킵니다</span>
<span class="nd">@Query</span><span class="o">(</span><span class="s">"""
SELECT new com.example.SimilarityDto(
b.id,
b.name,
SIMILARITY(b.name, :keyword)
) FROM Brand b
"""</span><span class="o">)</span>
<span class="nc">List</span><span class="o"><</span><span class="nc">SimilarityDto</span><span class="o">></span> <span class="nf">findSimilar</span><span class="o">(</span><span class="nd">@Param</span><span class="o">(</span><span class="s">"keyword"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">keyword</span><span class="o">);</span>
<span class="cm">/*
org.hibernate.query.SemanticException: Missing constructor for type 'com.example.SimilarityDto'
Caused by: java.lang.IllegalArgumentException: Could not find matching constructor
*/</span>
</code></pre></div></div>
<h3 id="12-해결-방법">1.2. 해결 방법</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ✅ 성공하는 케이스</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">SimilarityDto</span><span class="o">(</span>
<span class="no">UUID</span> <span class="n">id</span><span class="o">,</span>
<span class="nc">String</span> <span class="n">name</span><span class="o">,</span>
<span class="nc">Object</span> <span class="n">similarity</span> <span class="c1">// Object로 받아서 변환</span>
<span class="o">)</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nc">Double</span> <span class="nf">getSimilarity</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">((</span><span class="nc">Number</span><span class="o">)</span> <span class="n">similarity</span><span class="o">).</span><span class="na">doubleValue</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="2-데이터베이스-함수별-반환-타입과-자주-발생하는-에러">2. 데이터베이스 함수별 반환 타입과 자주 발생하는 에러</h2>
<h3 id="21-count-함수">2.1. COUNT 함수</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ❌ 실패 케이스</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">CountDto</span><span class="o">(</span><span class="nc">Integer</span> <span class="n">count</span><span class="o">)</span> <span class="o">{}</span> <span class="c1">// Integer 대신 Long 사용해야 함</span>
<span class="cm">/*
org.hibernate.query.SemanticException: Missing constructor for type 'CountDto'
Caused by: java.lang.IllegalArgumentException: No matching constructor
*/</span>
</code></pre></div></div>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ✅ 성공 케이스</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">CountDto</span><span class="o">(</span><span class="nc">Long</span> <span class="n">count</span><span class="o">)</span> <span class="o">{}</span>
</code></pre></div></div>
<h3 id="22-avg-함수">2.2. AVG 함수</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ❌ 실패 케이스</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">AvgDto</span><span class="o">(</span><span class="nc">Float</span> <span class="n">average</span><span class="o">)</span> <span class="o">{}</span> <span class="c1">// Float 대신 Double 사용해야 함</span>
<span class="cm">/*
org.hibernate.query.SemanticException: Missing constructor for type 'AvgDto'
Caused by: java.lang.IllegalArgumentException: No suitable constructor found
*/</span>
</code></pre></div></div>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ✅ 성공 케이스</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">AvgDto</span><span class="o">(</span><span class="nc">Double</span> <span class="n">average</span><span class="o">)</span> <span class="o">{}</span>
</code></pre></div></div>
<h2 id="3-계산된-필드의-타입-매칭">3. 계산된 필드의 타입 매칭</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ❌ 실패 케이스</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">PriceDto</span><span class="o">(</span>
<span class="nc">Long</span> <span class="n">id</span><span class="o">,</span>
<span class="nc">Integer</span> <span class="n">calculatedPrice</span> <span class="c1">// 계산 결과는 보통 Double</span>
<span class="o">)</span> <span class="o">{}</span>
<span class="nd">@Query</span><span class="o">(</span><span class="s">"""
SELECT new com.example.PriceDto(
p.id,
p.price * (1 - p.discount)
) FROM Product p
"""</span><span class="o">)</span>
<span class="cm">/*
org.hibernate.query.SemanticException: Missing constructor for type 'PriceDto'
Caused by: java.lang.IllegalArgumentException: Parameter type mismatch
*/</span>
</code></pre></div></div>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ✅ 성공 케이스 1: 명시적 캐스팅</span>
<span class="nd">@Query</span><span class="o">(</span><span class="s">"""
SELECT new com.example.PriceDto(
p.id,
CAST(p.price * (1 - p.discount) AS int)
) FROM Product p
"""</span><span class="o">)</span>
<span class="c1">// ✅ 성공 케이스 2: Object로 받기</span>
<span class="kd">public</span> <span class="n">record</span> <span class="nf">PriceDto</span><span class="o">(</span>
<span class="nc">Long</span> <span class="n">id</span><span class="o">,</span>
<span class="nc">Object</span> <span class="n">calculatedPrice</span>
<span class="o">)</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nc">Integer</span> <span class="nf">getCalculatedPrice</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">((</span><span class="nc">Number</span><span class="o">)</span> <span class="n">calculatedPrice</span><span class="o">).</span><span class="na">intValue</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="4-해결-전략">4. 해결 전략</h2>
<h3 id="41-디버깅을-위한-sql-로그-활성화">4.1. 디버깅을 위한 SQL 로그 활성화</h3>
<div class="language-properties highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># application.properties
</span><span class="py">spring.jpa.show-sql</span><span class="p">=</span><span class="s">true</span>
<span class="py">spring.jpa.properties.hibernate.format_sql</span><span class="p">=</span><span class="s">true</span>
</code></pre></div></div>
<h3 id="42-안전한-타입-변환-유틸리티">4.2. 안전한 타입 변환 유틸리티</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ProjectionUtils</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="nc">Double</span> <span class="nf">toDouble</span><span class="o">(</span><span class="nc">Object</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">value</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">value</span> <span class="k">instanceof</span> <span class="nc">Number</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="o">((</span><span class="nc">Number</span><span class="o">)</span> <span class="n">value</span><span class="o">).</span><span class="na">doubleValue</span><span class="o">();</span>
<span class="o">}</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">IllegalArgumentException</span><span class="o">(</span>
<span class="nc">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="s">"Cannot convert %s to Double: %s"</span><span class="o">,</span>
<span class="n">value</span><span class="o">.</span><span class="na">getClass</span><span class="o">(),</span> <span class="n">value</span><span class="o">)</span>
<span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h3 id="43-native-query-사용">4.3. Native Query 사용</h3>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@Query</span><span class="o">(</span>
<span class="n">value</span> <span class="o">=</span> <span class="s">"""
SELECT
id,
name,
CAST(SIMILARITY(name, :keyword) AS float8) as similarity
FROM brands
"""</span><span class="o">,</span>
<span class="n">nativeQuery</span> <span class="o">=</span> <span class="kc">true</span>
<span class="o">)</span>
<span class="nc">List</span><span class="o"><</span><span class="nc">SimilarityProjection</span><span class="o">></span> <span class="nf">findSimilar</span><span class="o">(</span><span class="nd">@Param</span><span class="o">(</span><span class="s">"keyword"</span><span class="o">)</span> <span class="nc">String</span> <span class="n">keyword</span><span class="o">);</span>
</code></pre></div></div>
<h2 id="결론">결론</h2>
<p>Spring Data JPA Projections에서 생성자 타입 매칭 오류를 해결하기 위한 핵심 포인트:</p>
<ol>
<li>데이터베이스 함수의 실제 반환 타입 확인</li>
<li>에러 메시지를 통한 정확한 원인 파악</li>
<li><code class="language-plaintext highlighter-rouge">Object</code> 또는 <code class="language-plaintext highlighter-rouge">Number</code>를 사용한 유연한 타입 처리</li>
<li>필요한 경우 명시적 타입 캐스팅 사용</li>
</ol>
<p>이러한 가이드라인을 따르면 “Missing constructor” 에러를 효과적으로 해결하고 안정적인 Projection을 구현할 수 있습니다.</p>
<p>#SpringBoot #JPA #Hibernate #DatabaseProjection #ErrorHandling #JavaTips</p>
Thu, 03 Apr 2025 01:30:00 +0000
https://anyjava.github.io/blog/2025/04/03/jpa-projects-error/
https://anyjava.github.io/blog/2025/04/03/jpa-projects-error/
SpringBoot
JPA
Hibernate
Database
ErrorHandling
Java
-
Welcome to Jekyll!
<p>You’ll find this post in your <code class="language-plaintext highlighter-rouge">_posts</code> directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run <code class="language-plaintext highlighter-rouge">jekyll serve</code>, which launches a web server and auto-regenerates your site when a file is updated.</p>
<p>To add new posts, simply add a file in the <code class="language-plaintext highlighter-rouge">_posts</code> directory that follows the convention <code class="language-plaintext highlighter-rouge">YYYY-MM-DD-name-of-post.ext</code> and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works.</p>
<p>Jekyll also offers powerful support for code snippets:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">def</span> <span class="nf">print_hi</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span>
<span class="nb">puts</span> <span class="s2">"Hi, </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">print_hi</span><span class="p">(</span><span class="s1">'Tom'</span><span class="p">)</span>
<span class="c1">#=> prints 'Hi, Tom' to STDOUT.</span></code></pre></figure>
<p>Check out the <a href="https://jekyllrb.com/docs/home">Jekyll docs</a> for more info on how to get the most out of Jekyll. File all bugs/feature requests at <a href="https://github.com/jekyll/jekyll">Jekyll’s GitHub repo</a>. If you have questions, you can ask them on <a href="https://talk.jekyllrb.com/">Jekyll Talk</a>.</p>
Fri, 24 Nov 2017 10:31:27 +0000
https://anyjava.github.io/blog/2017/11/24/welcome-to-jekyll/
https://anyjava.github.io/blog/2017/11/24/welcome-to-jekyll/
jekyll
update