본문으로 건너뛰기
ElastiCORE 3.0 은 릴리스 후보(RC)입니다: Maven Central 의 3.0.261022-rc1. 2.2 라인 프로젝트는 2.2 문서를 보세요.
버전: 3.0

필드와 타입

필드는 한 줄입니다: 이름: 타입[(크기)][!] [@annotations] -- 라벨.

값 타입 한눈에​

필드에 쓸 수 있는 값 타입 전부와, 생성되는 Java 타입, JSON 모양, TypeScript 타입, Apache Ossie 로 내보낼 때의 DataType.

DSL 타입JavaJSONTSOssie비고
string / string(n)String"text"stringStringn = 최대 길이, ! = NOT NULL
text / longtextString"text"stringStringcolumnDefinition = "TEXT" / "LONGTEXT"
clobString"text"stringString@Lob
jsonString"{...}" (문자열)stringOpaqueJSON 컬럼
int / IntegerInteger42numberInteger
long / LongLong42numberInteger
bigintegerBigInteger123456789012345678901numberInteger
quantityQuantity5numberInteger3.0 값 타입: 음수 없는 개수
decimal(p.s) / bigdecimal(p.s)BigDecimal12.34numberDecimalprecision, scale
money / money(p.s)Money99.95numberDecimal3.0 값 타입: 금액, 기본 (19,2)
float / doubleFloat / Double1.5numberFloat근사값 - 금액에 쓰지 마세요
booleanBooleantruebooleanBoolean
dateLocalDate"2026-10-03"stringDate
timeLocalTime"09:30:00"stringTime
datetimeLocalDateTime"2026-10-03 09:30:00"stringDateTime시간대 없음. ISO 의 T 가 아님
timestampjava.time.Instant"2026-10-03T00:30:00Z"stringDateTimeTz한 순간. UTC 로 돌려줌
blobbyte[]"AQID/w==" (base64)stringOpaque@Lob
EnumName그 enum코드 ("PLC")enumString@db(code) 의 값이 저장됨
EntityName참조(식별자 필드)-관계기본 @ManyToOne
  • 어느 시간 타입을 쓰나: 사람이 보는 날짜·시각(영업일, 예약 시각)은 date·datetime, "언제 일어났나"(결제 승인, 이벤트 발생, 감사)는 timestamp.
  • 표에 없는 타입은 쓰지 않습니다: uuid 는 string(36)(UUID 키는 string @id @genid), short·byte 는 int, char 는 string(1), OffsetDateTime·ZonedDateTime 은 timestamp.
  • 컬렉션: List<T>, Set<T>, Map<K,V>, 배열 int[], string[].
  • 표는 3.0 규칙 엔진 기준이고, 모든 타입을 elasticore-template-ddd 의 TypeRoundTripTest 가 생성·저장·HTTP 왕복으로 확인합니다.

money 와 quantity​

금액과 수량을 값 객체(io.elasticore.springboot3.domain)로 다룹니다. 컬럼과 JSON 은 그대로 decimal·integer 이고, 그 사이의 코드가 Money·Quantity 를 씁니다.

SalesOrderLine:
fields:
qty: quantity! @min(1)
unitPrice: money(12.2)! @min(0.01, '단가는 0보다 커야 한다')
amount: money(14.2)
line.setAmount(line.getUnitPrice().times(line.getQty()));
total = total.plus(line.getAmount());
stock.setOnHand(stock.getOnHand().minus(qty)); // 모자라면 422

Money: plus, minus, times(Quantity / long / BigDecimal), rounded(n)(반올림), isNegative - 10 과 10.00 은 같은 금액. Quantity 는 음수가 없습니다(0 밑으로 minus 하면 422 not enough). @default(0) 은 Money.of("0") / Quantity.of(0) 이 됩니다. 부호 있는 변화량(입고 +, 출고 -)은 수량이 아니므로 int 로 둡니다.

키​

쓰는 것뜻
id: long @id @sequenceDB 가 번호를 매김. 생성할 때 보내지 않음
id: string @id @genidUUID (UUID.randomUUID())
code: string(15) @id @genidIdUtils.newId(15): 3자 접두어 + 영숫자 12자
id: string @id @genid(com.acme.Ids.next)직접 만든 정적 메서드
isbn: string(13)! @id클라이언트가 보내는 키. 이미 있는 키로 생성하면 409

검증​

쓰는 것뜻
string(100)!필수, 100자까지 - "" 은 통과
string(100)! @notblank필수, 빈 값·공백만 있는 값 거절
string(20)! @length(min=4)4~20자
string(100) @email이메일 형식
int @min(1) @max(10)1~10 정수 (정수 필드에는 정수 값만, decimal·money 필드는 @DecimalMin/@DecimalMax)
money(10.2)! @min(0.01, 'price must be positive')최솟값과 메시지 - @DecimalMin
date @past, date @future오늘 이전 / 이후 (@pastorpresent, @futureorpresent 는 오늘 포함)
string(13)! @pattern('^[0-9]{13}$', 'ISBN must be 13 digits')값 전체가 정규식과 맞아야 함. 아니면 그 메시지로 400
lines: List<OrderLine> ... @minsize(1, 'an order needs a line')멤버 n개 이상. @maxsize(n, '...') 는 이하

@pattern: @pattern(regexp="...", message="...") 형식도 됩니다. 메시지를 생략하면 서버와 클라이언트 모두 "<라벨> is not in the expected form" 입니다. 백슬래시는 두 번(\\d) 쓰거나 [0-9] 같은 문자 클래스를 씁니다 - \d 하나면 DSL 경고. DTO 와 TypeScript 클라이언트에만 들어갑니다(엔티티·검색 DTO 에는 없음). 날짜 필드의 @pattern(yyyyMMdd) 는 지금처럼 날짜 형식입니다.

@minsize(n) 은 n 이 1 이상이면 @NotNull 도 붙습니다: 빈 목록도, 목록을 아예 보내지 않아도 400 이고, TypeScript 의 validate...() 도 같은 것을 묻습니다. DDD 번들에서는 루트가 저장 시점에도 검사합니다(422).

서버가 정하는 값​

쓰는 것뜻
joinedAt: date @readonly응답에는 나가고 요청으로는 받지 않으며 필수가 아님 - 내 코드(beforeSave)가 채움
grade: string(10)! @noinput같은 뜻(@noinput 은 별칭). 컬럼은 NOT NULL 그대로라 서버가 채워야 함
orderedAt: datetime @readonly @default(now)행을 만들 때의 시각 - 요청 값 무시, 수정해도 그대로
joinedOn: date @readonly @default(now)오늘
createdAt: datetime @updatable(false) @jpa:org.springframework.data.annotation.CreatedDate감사 필드 - @EnableJpaAuditing 필요
modifiedAt: datetime @jpa:org.springframework.data.annotation.LastModifiedDate저장할 때마다 바뀌는 값 (감사)

v3 번들에서 @readonly 는:

  • DTO 의 @NotNull·@NotBlank 를 빼고(요청이 보낼 수 없는 값이므로) @Schema(accessMode = READ_ONLY) 를 더합니다.
  • 매퍼가 DTO 에서 엔티티로 쓰지 않습니다. 서버 코드가 DTO 에 값을 넣고 저장하던 코드(dto.setGrade("A") 후 service.save(dto))는 그 값이 저장되지 않습니다 - 엔티티에 넣으세요(beforeSave, 루트의 메서드).
  • 엔티티 필드에 붙이면 그 엔티티의 모든 DTO 에, dto.yml 의 DTO 필드에 붙이면 그 DTO 에만 적용됩니다.

@default(now) 는 datetime 이면 LocalDateTime.now(), date·time·timestamp(Instant.now())도 now 를 받습니다 - 엔티티의 초기값이고 DTO 의 기본값이 아닙니다. @createtime 은 없습니다.

그 밖의 필드 어노테이션​

쓰는 것뜻
@default(값)기본값: @default("ACTIVE"), @default(true), @default(UserRole.USER)
@updatable(false)@Column(updatable = false). DDD 번들의 참조에 붙이면 ID 필드가 물려받아 수정해도 저장된 값이 남음
@writeonly요청으로 받고 응답에는 내보내지 않음 (카드 번호)
@password해시로만 저장 - 권한과 로그인
@access(admin)관리자만 쓰는 필드 - 권한과 로그인
@search(...)검색 조건 - 검색과 정렬
@formula("sql")DB 가 계산하는 컬럼 (Hibernate)
@Column(name="col", length=n) / @column(name)컬럼 매핑
@jpa:<어노테이션>JPA·Spring Data 어노테이션을 그대로
@env:이름env.yml 의 config.annotations 에 정의한 어노테이션
@terms(price, 가격)Ossie 로 나가는 동의어