forked from kimhyungsik/ax_hub_mcp_tool
feat(common, other): add GlowMciFieldInfo and List parsing support
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
package io.shinhanlife.glow;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface GlowMciFieldInfo {
|
||||
|
||||
/**
|
||||
* 필드 순서
|
||||
*/
|
||||
int order();
|
||||
|
||||
/**
|
||||
* 필드 길이 (List인 경우 전체 길이로 활용될 수 있음)
|
||||
*/
|
||||
int length();
|
||||
|
||||
/**
|
||||
* 필드 설명
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* List 매핑 시 대상 DTO 클래스
|
||||
*/
|
||||
Class<?> target() default void.class;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package io.shinhanlife.glow.util;
|
||||
|
||||
import io.shinhanlife.glow.GlowMciFieldInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.glow.util
|
||||
* @className GlowMciParser
|
||||
* @description MCI 고정 길이 전문 파싱 유틸리티 (GlowMciFieldInfo 기반)
|
||||
* @author 김형식
|
||||
* @create 2026.09.01
|
||||
*/
|
||||
@Slf4j
|
||||
public class GlowMciParser {
|
||||
|
||||
public static <T> T parse(String mciString, Class<T> clazz) {
|
||||
if (mciString == null || mciString.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
T instance = clazz.getDeclaredConstructor().newInstance();
|
||||
|
||||
List<Field> fields = new ArrayList<>();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(GlowMciFieldInfo.class)) {
|
||||
fields.add(field);
|
||||
}
|
||||
}
|
||||
|
||||
fields.sort(Comparator.comparingInt(f -> f.getAnnotation(GlowMciFieldInfo.class).order()));
|
||||
|
||||
int currentIndex = 0;
|
||||
for (Field field : fields) {
|
||||
GlowMciFieldInfo annotation = field.getAnnotation(GlowMciFieldInfo.class);
|
||||
int length = annotation.length();
|
||||
|
||||
if (currentIndex >= mciString.length()) {
|
||||
break;
|
||||
}
|
||||
|
||||
int endIndex = Math.min(currentIndex + length, mciString.length());
|
||||
String value = mciString.substring(currentIndex, endIndex);
|
||||
|
||||
field.setAccessible(true);
|
||||
setFieldValue(instance, field, value, annotation);
|
||||
|
||||
currentIndex += length;
|
||||
}
|
||||
|
||||
return instance;
|
||||
} catch (Exception e) {
|
||||
log.error("GlowMciFieldInfo 파싱 중 오류 발생: {}", e.getMessage(), e);
|
||||
throw new RuntimeException("MCI 전문 파싱 오류", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setFieldValue(Object instance, Field field, String value, GlowMciFieldInfo annotation) throws IllegalAccessException {
|
||||
Class<?> fieldType = field.getType();
|
||||
String trimmedValue = value.trim();
|
||||
|
||||
if (fieldType == String.class) {
|
||||
field.set(instance, trimmedValue);
|
||||
} else if (fieldType == int.class || fieldType == Integer.class) {
|
||||
field.set(instance, trimmedValue.isEmpty() ? 0 : Integer.parseInt(trimmedValue));
|
||||
} else if (fieldType == long.class || fieldType == Long.class) {
|
||||
field.set(instance, trimmedValue.isEmpty() ? 0L : Long.parseLong(trimmedValue));
|
||||
} else if (fieldType == boolean.class || fieldType == Boolean.class) {
|
||||
field.set(instance, Boolean.parseBoolean(trimmedValue));
|
||||
} else if (fieldType == double.class || fieldType == Double.class) {
|
||||
field.set(instance, trimmedValue.isEmpty() ? 0.0 : Double.parseDouble(trimmedValue));
|
||||
} else if (List.class.isAssignableFrom(fieldType)) {
|
||||
Class<?> targetClass = annotation.target();
|
||||
if (targetClass != void.class) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
int itemLength = calculateTotalLength(targetClass);
|
||||
if (itemLength > 0) {
|
||||
for (int i = 0; i < value.length(); i += itemLength) {
|
||||
int end = Math.min(i + itemLength, value.length());
|
||||
String itemStr = value.substring(i, end);
|
||||
if (itemStr.trim().isEmpty()) continue;
|
||||
list.add(parse(itemStr, targetClass));
|
||||
}
|
||||
}
|
||||
field.set(instance, list);
|
||||
}
|
||||
} else {
|
||||
field.set(instance, trimmedValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static int calculateTotalLength(Class<?> clazz) {
|
||||
int total = 0;
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
if (field.isAnnotationPresent(GlowMciFieldInfo.class)) {
|
||||
total += field.getAnnotation(GlowMciFieldInfo.class).length();
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.shinhanlife.axhub.biz.mcp.tool.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import io.shinhanlife.glow.GlowMciFieldInfo;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.axhub.biz.mcp.tool.dto
|
||||
* @className MciSampleStringRes
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 김형식
|
||||
* @create 2026.09.01
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class MciSampleStringRes {
|
||||
@GlowMciFieldInfo(order = 1, length = 10, description = "이름")
|
||||
private String name;
|
||||
|
||||
@GlowMciFieldInfo(order = 2, length = 3, description = "나이")
|
||||
private int age;
|
||||
|
||||
@GlowMciFieldInfo(order = 3, length = 8, description = "가입일자(YYYYMMDD)")
|
||||
private String joinDate;
|
||||
|
||||
@GlowMciFieldInfo(order = 4, length = 2, description = "상태코드")
|
||||
private String statusCode;
|
||||
|
||||
@GlowMciFieldInfo(order = 5, length = 30, description = "타겟 리스트", target = MciSampleTargetDto.class)
|
||||
private List<MciSampleTargetDto> targetList;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package io.shinhanlife.axhub.biz.mcp.tool.dto;
|
||||
|
||||
import io.shinhanlife.glow.GlowMciFieldInfo;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @package io.shinhanlife.axhub.biz.mcp.tool.dto
|
||||
* @className MciSampleTargetDto
|
||||
* @description AX HUB 시스템 처리 클래스
|
||||
* @author 김형식
|
||||
* @create 2026.09.01
|
||||
*/
|
||||
@Data
|
||||
public class MciSampleTargetDto {
|
||||
@GlowMciFieldInfo(order = 1, length = 5, description = "항목 코드")
|
||||
private String itemCode;
|
||||
|
||||
@GlowMciFieldInfo(order = 2, length = 5, description = "항목 값")
|
||||
private String itemValue;
|
||||
}
|
||||
@@ -2,9 +2,8 @@ package io.shinhanlife.axhub.biz.mcp.tool.service;
|
||||
|
||||
import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpFunction;
|
||||
import io.shinhanlife.axhub.biz.mcp.tool.annotation.McpTool;
|
||||
import io.shinhanlife.axhub.biz.mcp.tool.dto.MciSampleStringRes;
|
||||
import io.shinhanlife.axhub.biz.mcp.tool.dto.SampleStringReq;
|
||||
import io.shinhanlife.axhub.biz.mcp.tool.dto.SampleStringRes;
|
||||
import io.shinhanlife.glow.util.GlowTrgmParser;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
@@ -44,7 +43,7 @@ public class SampleStringToolService extends AbstractMcpToolService {
|
||||
|
||||
String rawStringResponse = (String) result.get("legacy_response");
|
||||
|
||||
// 2. 받아온 고정 길이 전문(String)을 GlowTrgmParser를 이용해 DTO로 파싱합니다.
|
||||
return GlowTrgmParser.parse(rawStringResponse, SampleStringRes.class);
|
||||
// 2. 받아온 고정 길이 전문(String)을 GlowMciParser를 이용해 DTO로 파싱합니다.
|
||||
return io.shinhanlife.glow.util.GlowMciParser.parse(rawStringResponse, MciSampleStringRes.class);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user