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());
|
throw new InvalidAccessException("The number of repetitions is different from the number of repetitions of the actual data. , " + item.getName(), item.getItemPath());
|
||||||
}
|
}
|
||||||
} // validation
|
} // validation
|
||||||
|
} catch(InvalidAccessException e) {
|
||||||
|
throw e;
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
throw new InvalidAccessException("setValue error", getItemPath(), null, e);
|
throw new InvalidAccessException("setValue error", getItemPath(), null, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doSetValue(JsonNode node, HashMap validationTargets, String parentPath) {
|
protected void doSetValue(JsonNode node, HashMap validationTargets, String parentPath) {
|
||||||
Item item = null;
|
Item item = null;
|
||||||
@@ -255,40 +257,49 @@ public class JSONMessage extends Message {
|
|||||||
} else if(value == null || value.length() == 0) {
|
} else if(value == null || value.length() == 0) {
|
||||||
setObject( itemPath, value );
|
setObject( itemPath, value );
|
||||||
} else {
|
} else {
|
||||||
int itemType = item.getDataTypeId();
|
int itemType = item.getDataTypeId();
|
||||||
switch(itemType) {
|
try {
|
||||||
case Types.TYPE_INT :
|
switch(itemType) {
|
||||||
case Types.TYPE_SHORT :
|
case Types.TYPE_INT :
|
||||||
setInt( itemPath, new Integer(value) );
|
case Types.TYPE_SHORT :
|
||||||
break;
|
setInt( itemPath, new Integer(value) );
|
||||||
case Types.TYPE_LONG :
|
break;
|
||||||
setLong( itemPath, new Long(value) );
|
case Types.TYPE_LONG :
|
||||||
break;
|
setLong( itemPath, new Long(value) );
|
||||||
case Types.TYPE_BIGDECIMAL :
|
break;
|
||||||
if (SystemKeys.isValidationEnabled() && !isValid(value, item.getLength(), item.getDecimalPointLength())) {
|
case Types.TYPE_BIGDECIMAL :
|
||||||
throw new InvalidAccessException(
|
if (SystemKeys.isValidationEnabled() && !isValid(value, item.getLength(), item.getDecimalPointLength())) {
|
||||||
String.format("Invalid decimal point format Error value=%s,length=%d,pointLength=%d",
|
throw new InvalidAccessException(
|
||||||
value, item.getLength(), item.getDecimalPointLength()),
|
String.format("Invalid decimal point format Error value=%s,length=%d,pointLength=%d",
|
||||||
itemPath);
|
value, item.getLength(), item.getDecimalPointLength()),
|
||||||
}
|
itemPath);
|
||||||
setBigDecimal( itemPath, new BigDecimal(value) );
|
}
|
||||||
break;
|
setBigDecimal( itemPath, new BigDecimal(value) );
|
||||||
case Types.TYPE_DOUBLE :
|
break;
|
||||||
setDouble( itemPath, new Double(value) );
|
case Types.TYPE_DOUBLE :
|
||||||
break;
|
setDouble( itemPath, new Double(value) );
|
||||||
case Types.TYPE_FLOAT :
|
break;
|
||||||
setFloat( itemPath, new Float(value) );
|
case Types.TYPE_FLOAT :
|
||||||
break;
|
setFloat( itemPath, new Float(value) );
|
||||||
case Types.TYPE_BOOLEAN :
|
break;
|
||||||
setObject( itemPath, new Boolean(value) );
|
case Types.TYPE_BOOLEAN :
|
||||||
break;
|
setObject( itemPath, new Boolean(value) );
|
||||||
case Types.TYPE_STRING :
|
break;
|
||||||
setString(itemPath, value);
|
case Types.TYPE_STRING :
|
||||||
break;
|
setString(itemPath, value);
|
||||||
default :
|
break;
|
||||||
setString(itemPath, value);
|
default :
|
||||||
break;
|
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
|
* - LONG_VALUE : LONG, length=10, decimal=0
|
||||||
* - BIG_VALUE : BIGDECIMAL, length=10, decimal=5 → 정수부 최대 4자리
|
* - BIG_VALUE : BIGDECIMAL, length=10, decimal=5 → 정수부 최대 4자리
|
||||||
* - BIG15_VALUE : BIGDECIMAL, length=15, decimal=0 → 정수부 최대 15자리
|
* - BIG15_VALUE : BIGDECIMAL, length=15, decimal=0 → 정수부 최대 15자리
|
||||||
|
* - STR_VALUE : STRING, length=20
|
||||||
*
|
*
|
||||||
* 검증 시나리오
|
* 검증 시나리오
|
||||||
* 1) 타입 불일치 — 숫자형 필드에 비숫자 문자열 입력 시 setData() 에서 즉시 오류
|
* 1-a) 타입 불일치(오류) — 숫자형 필드에 비숫자 문자열 입력 시 setData() 에서 즉시 오류
|
||||||
* 2) 길이 초과 — BigDecimal 정수부/소수부 자릿수 초과 시 setData() 에서 즉시 오류
|
* 1-b) 타입 불일치(정상) — 숫자형 필드에 숫자 문자열 입력 시 파싱 가능하면 정상 처리
|
||||||
* (SystemKeys.TRANSFROMER_VALIDATION=true 필요)
|
* 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
|
@DataJpaTest
|
||||||
@ContextConfiguration(classes = { TransformJPATestConfiguration.class })
|
@ContextConfiguration(classes = { TransformJPATestConfiguration.class })
|
||||||
@@ -110,8 +115,82 @@ class JSONMessageValidationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────────
|
||||||
// 2. 숫자형 길이 초과 테스트 — setData() 시점에 오류 발생
|
// 1-b. 숫자형 필드에 숫자 문자열 입력 → 정상 처리
|
||||||
// transformer.validation=true 설정 필요
|
// 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
|
@Test
|
||||||
@@ -180,6 +259,102 @@ class JSONMessageValidationTest {
|
|||||||
assertTrue(result.contains("BIG_VALUE"), "BIG_VALUE가 결과에 포함되어야 합니다");
|
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', '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', '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', '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