JSON 메시지 validation 기능 수정
- 오류발생위치 출력 - type 오류 validation test 추가
This commit is contained in:
@@ -166,10 +166,12 @@ public class JSONMessage extends Message {
|
||||
throw new InvalidAccessException("The number of repetitions is different from the number of repetitions of the actual data. , " + item.getName(), item.getItemPath());
|
||||
}
|
||||
} // validation
|
||||
} catch(InvalidAccessException e) {
|
||||
throw e;
|
||||
} catch(Exception e) {
|
||||
throw new InvalidAccessException("setValue error", getItemPath(), null, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void doSetValue(JsonNode node, HashMap validationTargets, String parentPath) {
|
||||
Item item = null;
|
||||
@@ -255,40 +257,49 @@ public class JSONMessage extends Message {
|
||||
} else if(value == null || value.length() == 0) {
|
||||
setObject( itemPath, value );
|
||||
} else {
|
||||
int itemType = item.getDataTypeId();
|
||||
switch(itemType) {
|
||||
case Types.TYPE_INT :
|
||||
case Types.TYPE_SHORT :
|
||||
setInt( itemPath, new Integer(value) );
|
||||
break;
|
||||
case Types.TYPE_LONG :
|
||||
setLong( itemPath, new Long(value) );
|
||||
break;
|
||||
case Types.TYPE_BIGDECIMAL :
|
||||
if (SystemKeys.isValidationEnabled() && !isValid(value, item.getLength(), item.getDecimalPointLength())) {
|
||||
throw new InvalidAccessException(
|
||||
String.format("Invalid decimal point format Error value=%s,length=%d,pointLength=%d",
|
||||
value, item.getLength(), item.getDecimalPointLength()),
|
||||
itemPath);
|
||||
}
|
||||
setBigDecimal( itemPath, new BigDecimal(value) );
|
||||
break;
|
||||
case Types.TYPE_DOUBLE :
|
||||
setDouble( itemPath, new Double(value) );
|
||||
break;
|
||||
case Types.TYPE_FLOAT :
|
||||
setFloat( itemPath, new Float(value) );
|
||||
break;
|
||||
case Types.TYPE_BOOLEAN :
|
||||
setObject( itemPath, new Boolean(value) );
|
||||
break;
|
||||
case Types.TYPE_STRING :
|
||||
setString(itemPath, value);
|
||||
break;
|
||||
default :
|
||||
setString(itemPath, value);
|
||||
break;
|
||||
}
|
||||
int itemType = item.getDataTypeId();
|
||||
try {
|
||||
switch(itemType) {
|
||||
case Types.TYPE_INT :
|
||||
case Types.TYPE_SHORT :
|
||||
setInt( itemPath, new Integer(value) );
|
||||
break;
|
||||
case Types.TYPE_LONG :
|
||||
setLong( itemPath, new Long(value) );
|
||||
break;
|
||||
case Types.TYPE_BIGDECIMAL :
|
||||
if (SystemKeys.isValidationEnabled() && !isValid(value, item.getLength(), item.getDecimalPointLength())) {
|
||||
throw new InvalidAccessException(
|
||||
String.format("Invalid decimal point format Error value=%s,length=%d,pointLength=%d",
|
||||
value, item.getLength(), item.getDecimalPointLength()),
|
||||
itemPath);
|
||||
}
|
||||
setBigDecimal( itemPath, new BigDecimal(value) );
|
||||
break;
|
||||
case Types.TYPE_DOUBLE :
|
||||
setDouble( itemPath, new Double(value) );
|
||||
break;
|
||||
case Types.TYPE_FLOAT :
|
||||
setFloat( itemPath, new Float(value) );
|
||||
break;
|
||||
case Types.TYPE_BOOLEAN :
|
||||
setObject( itemPath, new Boolean(value) );
|
||||
break;
|
||||
case Types.TYPE_STRING :
|
||||
setString(itemPath, value);
|
||||
break;
|
||||
default :
|
||||
setString(itemPath, value);
|
||||
break;
|
||||
}
|
||||
} catch (InvalidAccessException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new InvalidAccessException(
|
||||
String.format("Type mismatch: value='%s', field='%s', dataType=%s",
|
||||
value, itemPath, Types.getType(itemType)),
|
||||
itemPath, null, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,16 @@ import com.eactive.eai.transformer.message.MessageSetDataException;
|
||||
* - LONG_VALUE : LONG, length=10, decimal=0
|
||||
* - BIG_VALUE : BIGDECIMAL, length=10, decimal=5 → 정수부 최대 4자리
|
||||
* - BIG15_VALUE : BIGDECIMAL, length=15, decimal=0 → 정수부 최대 15자리
|
||||
* - STR_VALUE : STRING, length=20
|
||||
*
|
||||
* 검증 시나리오
|
||||
* 1) 타입 불일치 — 숫자형 필드에 비숫자 문자열 입력 시 setData() 에서 즉시 오류
|
||||
* 2) 길이 초과 — BigDecimal 정수부/소수부 자릿수 초과 시 setData() 에서 즉시 오류
|
||||
* (SystemKeys.TRANSFROMER_VALIDATION=true 필요)
|
||||
* 1-a) 타입 불일치(오류) — 숫자형 필드에 비숫자 문자열 입력 시 setData() 에서 즉시 오류
|
||||
* 1-b) 타입 불일치(정상) — 숫자형 필드에 숫자 문자열 입력 시 파싱 가능하면 정상 처리
|
||||
* 2-a) Java 타입 범위 초과 — INT/LONG 최대값 초과 시 NumberFormatException (validation 설정 무관)
|
||||
* 2-b) BigDecimal 자릿수 초과 (숫자 리터럴) — 정수부/소수부 자릿수 초과 시 즉시 오류
|
||||
* 2-c) BigDecimal 자릿수 초과 (문자열 형태) — JSON 문자열로 전달된 경우도 동일하게 검증
|
||||
* (2-b, 2-c 모두 SystemKeys.TRANSFROMER_VALIDATION=true 필요)
|
||||
* 3) 역방향 타입 — 문자열 필드에 JSON 숫자 입력 시 asText()로 자동 변환 → 오류 없음
|
||||
*/
|
||||
@DataJpaTest
|
||||
@ContextConfiguration(classes = { TransformJPATestConfiguration.class })
|
||||
@@ -110,8 +115,82 @@ class JSONMessageValidationTest {
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// 2. 숫자형 길이 초과 테스트 — setData() 시점에 오류 발생
|
||||
// transformer.validation=true 설정 필요
|
||||
// 1-b. 숫자형 필드에 숫자 문자열 입력 → 정상 처리
|
||||
// JSON 문자열 노드라도 파싱 가능한 숫자면 오류 없이 처리됨
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@DisplayName("INT 타입 필드에 숫자 문자열 입력 → 오류 없이 정상 처리")
|
||||
void testIntFieldWithNumericString() throws Exception {
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"INT_VALUE\":\"42\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
msg.setData(data);
|
||||
|
||||
String result = (String) msg.getData();
|
||||
assertNotNull(result, "결과값이 null이 아니어야 합니다");
|
||||
assertTrue(result.contains("\"INT_VALUE\":42"), "INT_VALUE가 숫자 42로 출력되어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("LONG 타입 필드에 숫자 문자열 입력 → 오류 없이 정상 처리")
|
||||
void testLongFieldWithNumericString() throws Exception {
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"LONG_VALUE\":\"9876543210\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
msg.setData(data);
|
||||
|
||||
String result = (String) msg.getData();
|
||||
assertNotNull(result, "결과값이 null이 아니어야 합니다");
|
||||
assertTrue(result.contains("\"LONG_VALUE\":9876543210"), "LONG_VALUE가 숫자 9876543210으로 출력되어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("BIGDECIMAL 타입 필드에 숫자 문자열 입력 → 오류 없이 정상 처리")
|
||||
void testBigDecimalFieldWithNumericString() throws Exception {
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG_VALUE\":\"1234.12345\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
msg.setData(data);
|
||||
|
||||
String result = (String) msg.getData();
|
||||
assertNotNull(result, "결과값이 null이 아니어야 합니다");
|
||||
assertTrue(result.contains("\"BIG_VALUE\":1234.12345"), "BIG_VALUE가 숫자 1234.12345로 출력되어야 합니다");
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// 2-a. INT/LONG Java 타입 범위 초과 — validation 설정 무관하게 NumberFormatException
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@DisplayName("INT 타입 필드에 Integer 최대값 초과 입력 → NumberFormatException")
|
||||
void testIntFieldJavaTypeOverflow() {
|
||||
// Integer.MAX_VALUE = 2147483647, 초과값 → new Integer() 파싱 실패
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"INT_VALUE\":\"2147483648\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
|
||||
MessageSetDataException ex = assertThrows(
|
||||
MessageSetDataException.class,
|
||||
() -> msg.setData(data)
|
||||
);
|
||||
assertTrue(containsCause(ex, NumberFormatException.class),
|
||||
"원인이 NumberFormatException이어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("LONG 타입 필드에 Long 최대값 초과 입력 → NumberFormatException")
|
||||
void testLongFieldJavaTypeOverflow() {
|
||||
// Long.MAX_VALUE = 9223372036854775807, 초과값 → new Long() 파싱 실패
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"LONG_VALUE\":\"9223372036854775808\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
|
||||
MessageSetDataException ex = assertThrows(
|
||||
MessageSetDataException.class,
|
||||
() -> msg.setData(data)
|
||||
);
|
||||
assertTrue(containsCause(ex, NumberFormatException.class),
|
||||
"원인이 NumberFormatException이어야 합니다");
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// 2-b. BigDecimal 자릿수 초과 (JSON 숫자 리터럴) — transformer.validation=true 필요
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@@ -180,6 +259,102 @@ class JSONMessageValidationTest {
|
||||
assertTrue(result.contains("BIG_VALUE"), "BIG_VALUE가 결과에 포함되어야 합니다");
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// 2-c. BigDecimal 자릿수 초과 (JSON 문자열 형태) — transformer.validation=true 필요
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@DisplayName("BIG_VALUE 정수부 초과 문자열 입력(5자리 > 4자리 제한) → MessageSetDataException")
|
||||
void testBigDecimalIntegerPartOverflowFromString() {
|
||||
enableValidation();
|
||||
|
||||
// JSON 문자열 "12345.12345" → 정수부 5자리 초과
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG_VALUE\":\"12345.12345\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
|
||||
MessageSetDataException ex = assertThrows(
|
||||
MessageSetDataException.class,
|
||||
() -> msg.setData(data)
|
||||
);
|
||||
assertTrue(containsMessage(ex, "Invalid decimal point format"),
|
||||
"'Invalid decimal point format' 메시지가 포함되어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("BIG_VALUE 소수부 초과 문자열 입력(6자리 > 5자리 제한) → MessageSetDataException")
|
||||
void testBigDecimalFractionalPartOverflowFromString() {
|
||||
enableValidation();
|
||||
|
||||
// JSON 문자열 "1234.123456" → 소수부 6자리 초과
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG_VALUE\":\"1234.123456\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
|
||||
MessageSetDataException ex = assertThrows(
|
||||
MessageSetDataException.class,
|
||||
() -> msg.setData(data)
|
||||
);
|
||||
assertTrue(containsMessage(ex, "Invalid decimal point format"),
|
||||
"'Invalid decimal point format' 메시지가 포함되어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("BIG15_VALUE 정수부 초과 문자열 입력(16자리 > 15자리 제한) → MessageSetDataException")
|
||||
void testBigDecimalIntegerOnlyOverflowFromString() {
|
||||
enableValidation();
|
||||
|
||||
// JSON 문자열 "1234567890123456" → 정수부 16자리 초과
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"BIG15_VALUE\":\"1234567890123456\"}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
|
||||
MessageSetDataException ex = assertThrows(
|
||||
MessageSetDataException.class,
|
||||
() -> msg.setData(data)
|
||||
);
|
||||
assertTrue(containsMessage(ex, "Invalid decimal point format"),
|
||||
"'Invalid decimal point format' 메시지가 포함되어야 합니다");
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// 3. 역방향 타입 테스트 — 문자열 필드에 숫자 입력 → 정상 처리
|
||||
// JSON 숫자 노드는 node.asText()로 문자열 변환되어 오류 없이 처리됨
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@DisplayName("STRING 타입 필드에 JSON 정수 입력 → 오류 없이 정상 처리")
|
||||
void testStringFieldWithIntegerValue() throws Exception {
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"STR_VALUE\":123}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
msg.setData(data);
|
||||
|
||||
String result = (String) msg.getData();
|
||||
assertNotNull(result, "결과값이 null이 아니어야 합니다");
|
||||
assertTrue(result.contains("STR_VALUE"), "STR_VALUE가 결과에 포함되어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("STRING 타입 필드에 JSON 실수 입력 → 오류 없이 정상 처리")
|
||||
void testStringFieldWithDecimalValue() throws Exception {
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"STR_VALUE\":12.34}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
msg.setData(data);
|
||||
|
||||
String result = (String) msg.getData();
|
||||
assertNotNull(result, "결과값이 null이 아니어야 합니다");
|
||||
assertTrue(result.contains("STR_VALUE"), "STR_VALUE가 결과에 포함되어야 합니다");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("STRING 타입 필드에 JSON 큰 정수 입력 → 오류 없이 정상 처리")
|
||||
void testStringFieldWithLargeIntegerValue() throws Exception {
|
||||
String data = "{\"EAI_UJSONTYPE_REQ1\":{\"STR_VALUE\":9876543210}}";
|
||||
Message msg = MessageFactory.getFactory().getMessage("EAI_UJSONTYPE_REQ1");
|
||||
msg.setData(data);
|
||||
|
||||
String result = (String) msg.getData();
|
||||
assertNotNull(result, "결과값이 null이 아니어야 합니다");
|
||||
assertTrue(result.contains("STR_VALUE"), "STR_VALUE가 결과에 포함되어야 합니다");
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
// 유틸 메서드
|
||||
// ─────────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -6,4 +6,5 @@ INSERT INTO TSEAITR08 (loutname,loutitemname,loutitemserno,loutitemidname,parntl
|
||||
('EAI_UJSONTYPE_REQ1', 'INT_VALUE', 1, 9001, 9000, 'INT 타입 필드', 2203, 2102, NULL, 5, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'Integer', 0, NULL, NULL),
|
||||
('EAI_UJSONTYPE_REQ1', 'LONG_VALUE', 2, 9002, 9000, 'LONG 타입 필드', 2203, 2103, NULL, 10, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'Long', 0, NULL, NULL),
|
||||
('EAI_UJSONTYPE_REQ1', 'BIG_VALUE', 3, 9003, 9000, 'BIGDECIMAL length=10 decimal=5', 2203, 2118, NULL, 10, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 5, 'BigDecimal', 0, NULL, NULL),
|
||||
('EAI_UJSONTYPE_REQ1', 'BIG15_VALUE', 4, 9004, 9000, 'BIGDECIMAL length=15 decimal=0', 2203, 2118, NULL, 15, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'BigDecimal', 0, NULL, NULL);
|
||||
('EAI_UJSONTYPE_REQ1', 'BIG15_VALUE', 4, 9004, 9000, 'BIGDECIMAL length=15 decimal=0', 2203, 2118, NULL, 15, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'BigDecimal', 0, NULL, NULL),
|
||||
('EAI_UJSONTYPE_REQ1', 'STR_VALUE', 5, 9005, 9000, 'STRING 타입 필드', 2203, 2101, NULL, 20, NULL, NULL, NULL, 1, 1, NULL, 'N', 2, 0, 'String', 0, NULL, NULL);
|
||||
|
||||
Reference in New Issue
Block a user