update: apply recent changes from local workspace
All checks were successful
Deploy to OCIWP / deploy (push) Successful in 1m54s

This commit is contained in:
jade
2026-08-13 09:52:18 +09:00
parent fc235f05b9
commit df03037d3f
22 changed files with 559 additions and 313 deletions

View File

@@ -98,22 +98,33 @@ public class ToolScaffolder {
Files.createDirectories(mockDir);
String bizPackage = BASE_PACKAGE + ".biz." + group;
writeUtf8(useCaseDir.resolve(useCaseBaseName + "UseCase.java"),
groupedUseCaseContent(bizPackage, useCaseBaseName, moduleName, tools));
writeUtf8(implDir.resolve(useCaseBaseName + "UseCaseImpl.java"),
groupedUseCaseImplContent(bizPackage, useCaseBaseName, tools));
writeUtf8(converterDir.resolve(useCaseBaseName + "Converter.java"),
groupedConverterContent(bizPackage, useCaseBaseName, tools));
Path useCaseFile = useCaseDir.resolve(useCaseBaseName + "UseCase.java");
Path useCaseImplFile = implDir.resolve(useCaseBaseName + "UseCaseImpl.java");
Path converterFile = converterDir.resolve(useCaseBaseName + "Converter.java");
boolean existingUseCase = Files.exists(useCaseFile);
if (existingUseCase) {
appendGroupedUseCaseSources(useCaseFile, useCaseImplFile, converterFile, bizPackage, useCaseBaseName,
moduleName, tools);
} else {
writeUtf8(useCaseFile, groupedUseCaseContent(bizPackage, useCaseBaseName, moduleName, tools));
writeUtf8(useCaseImplFile, groupedUseCaseImplContent(bizPackage, useCaseBaseName, tools));
writeUtf8(converterFile, groupedConverterContent(bizPackage, useCaseBaseName, tools));
}
StringBuilder log = new StringBuilder("\n=========================================\n")
.append(" Multi Tool Scaffolding Complete\n")
.append("=========================================\n")
.append("[Usecase Interface] ").append(useCaseDir.resolve(useCaseBaseName + "UseCase.java")).append("\n")
.append("[Usecase Impl] ").append(implDir.resolve(useCaseBaseName + "UseCaseImpl.java")).append("\n");
.append(existingUseCase ? " Existing UseCase Extended\n" : " New UseCase Created\n")
.append("[Usecase Interface] ").append(useCaseFile).append("\n")
.append("[Usecase Impl] ").append(useCaseImplFile).append("\n");
for (ToolMethodDefinition tool : tools) {
writeGroupedToolFiles(moduleRoot, sourceRoot, dtoDir, definitionDir, mockDir, bizPackage, tool, moduleName, log);
if ("HTTP".equalsIgnoreCase(tool.routingType())) {
ensureLocalHttpApiConfiguration(moduleRoot, tool.httpApiName(),
toToolName(moduleName, tool.group(), toPascalCase(tool.baseName())));
}
}
log.append("[Converter] ").append(converterDir.resolve(useCaseBaseName + "Converter.java")).append("\n");
log.append("[Converter] ").append(converterFile).append("\n");
return log.toString();
}
@@ -128,13 +139,18 @@ public class ToolScaffolder {
if (!expectedGroup.equalsIgnoreCase(tool.group())) {
throw new IllegalArgumentException("All Tool methods in one UseCase must use the same category.");
}
if (!"MCI".equalsIgnoreCase(tool.routingType())) {
throw new IllegalArgumentException("Grouped Tool scaffolding currently supports MCI Tools only.");
boolean mci = "MCI".equalsIgnoreCase(tool.routingType());
boolean http = "HTTP".equalsIgnoreCase(tool.routingType());
if (!mci && !http) {
throw new IllegalArgumentException("Grouped Tool supports only MCI or HTTP routing.");
}
if (tool.interfaceId() == null || tool.interfaceId().isBlank()
|| tool.clientSystemCode() == null || tool.clientSystemCode().isBlank()) {
if (mci && (tool.interfaceId() == null || tool.interfaceId().isBlank()
|| tool.clientSystemCode() == null || tool.clientSystemCode().isBlank())) {
throw new IllegalArgumentException("MCI Tool needs an interface ID and Client system code.");
}
if (http && (tool.httpApiName() == null || tool.httpApiName().isBlank())) {
throw new IllegalArgumentException("HTTP Tool needs an HTTP API name.");
}
String toolName = toToolName("", tool.group(), toPascalCase(tool.baseName()));
if (!methods.add(tool.methodName()) || !toolNames.add(toolName)) {
throw new IllegalArgumentException("Tool method names and MCP Tool names must be unique.");
@@ -146,9 +162,10 @@ public class ToolScaffolder {
Path mockDir, String bizPackage, ToolMethodDefinition tool,
String moduleName, StringBuilder log) throws IOException {
String baseName = toPascalCase(tool.baseName());
String code = tool.clientSystemCode().toLowerCase(Locale.ROOT);
String ioPackage = BASE_PACKAGE + ".infra.itrf.mci." + code;
Path clientDir = sourceRoot.resolve(Paths.get("infra", "itrf", "mci", code));
boolean mci = "MCI".equalsIgnoreCase(tool.routingType());
String code = mci ? tool.clientSystemCode().toLowerCase(Locale.ROOT) : toPackageSegment(tool.httpApiName());
String ioPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." : ".infra.itrf.http.") + code;
Path clientDir = sourceRoot.resolve(Paths.get("infra", "itrf", mci ? "mci" : "http", code));
Path ioDir = clientDir.resolve("io");
Files.createDirectories(ioDir);
writeUtf8(dtoDir.resolve(baseName + "Request.java"),
@@ -157,14 +174,29 @@ public class ToolScaffolder {
dtoContent(bizPackage + ".dto", baseName + "Response", tool.outputFields(), "", "", false));
writeStructuredFieldTypes(dtoDir, bizPackage + ".dto", baseName + "Request", tool.inputFields());
writeStructuredFieldTypes(dtoDir, bizPackage + ".dto", baseName + "Response", tool.outputFields());
writeUtf8(ioDir.resolve(baseName + "_I.java"),
mciIoContent("infra.itrf.mci." + code, baseName + "_I", tool.inputFields(), "", ""));
writeUtf8(ioDir.resolve(baseName + "_O.java"),
mciIoContent("infra.itrf.mci." + code, baseName + "_O", tool.outputFields(), "", ""));
writeStructuredFieldTypes(ioDir, ioPackage + ".io", baseName + "_I", tool.inputFields());
writeStructuredFieldTypes(ioDir, ioPackage + ".io", baseName + "_O", tool.outputFields());
writeUtf8(clientDir.resolve(baseName + "Client.java"),
groupedMciClientContent(ioPackage, baseName, tool.interfaceId()));
if (mci) {
writeUtf8(ioDir.resolve(baseName + "_I.java"),
mciIoContent("infra.itrf.mci." + code, baseName + "_I", tool.inputFields(), "", ""));
writeUtf8(ioDir.resolve(baseName + "_O.java"),
mciIoContent("infra.itrf.mci." + code, baseName + "_O", tool.outputFields(), "", ""));
writeStructuredFieldTypes(ioDir, ioPackage + ".io", baseName + "_I", tool.inputFields());
writeStructuredFieldTypes(ioDir, ioPackage + ".io", baseName + "_O", tool.outputFields());
writeUtf8(clientDir.resolve(baseName + "Client.java"),
groupedMciClientContent(ioPackage, baseName, tool.interfaceId()));
writeUtf8(sourceRoot.resolve(Paths.get("biz", tool.group().toLowerCase(Locale.ROOT), "converter", baseName + "Converter.java")),
groupedMciConverterContent(bizPackage, baseName, ioPackage));
} else {
writeUtf8(ioDir.resolve(baseName + "HttpRequest.java"),
dtoContent(ioPackage + ".io", baseName + "HttpRequest", tool.inputFields(), "", "", true));
writeUtf8(ioDir.resolve(baseName + "HttpResponse.java"),
dtoContent(ioPackage + ".io", baseName + "HttpResponse", tool.outputFields(), "", "", false));
writeStructuredFieldTypes(ioDir, ioPackage + ".io", baseName + "HttpRequest", tool.inputFields());
writeStructuredFieldTypes(ioDir, ioPackage + ".io", baseName + "HttpResponse", tool.outputFields());
writeUtf8(clientDir.resolve(baseName + "Client.java"),
httpClientContent(ioPackage, baseName + "Client", tool.httpApiName()));
writeUtf8(sourceRoot.resolve(Paths.get("biz", tool.group().toLowerCase(Locale.ROOT), "converter", baseName + "Converter.java")),
groupedHttpConverterContent(bizPackage, baseName, ioPackage));
}
String toolName = toToolName(moduleName, tool.group(), baseName);
writeUtf8(definitionDir.resolve(toolName + ".yml"), toolDefinitionContentV17(toolName,
@@ -204,48 +236,154 @@ public class ToolScaffolder {
StringBuilder methods = new StringBuilder();
for (ToolMethodDefinition tool : tools) {
String baseName = toPascalCase(tool.baseName());
String code = tool.clientSystemCode().toLowerCase(Locale.ROOT);
String clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client";
String converterVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Converter";
boolean mci = "MCI".equalsIgnoreCase(tool.routingType());
String integrationPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." + tool.clientSystemCode().toLowerCase(Locale.ROOT)
: ".infra.itrf.http." + toPackageSegment(tool.httpApiName()));
imports.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Request;\n")
.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n")
.append("import ").append(BASE_PACKAGE).append(".infra.itrf.mci.").append(code).append(".").append(baseName).append("Client;\n")
.append("import ").append(BASE_PACKAGE).append(".infra.itrf.mci.").append(code).append(".io.").append(baseName).append("_I;\n")
.append("import ").append(BASE_PACKAGE).append(".infra.itrf.mci.").append(code).append(".io.").append(baseName).append("_O;\n");
.append("import ").append(bizPackage).append(".converter.").append(baseName).append("Converter;\n")
.append("import ").append(integrationPackage).append(".").append(baseName).append("Client;\n")
.append("import ").append(integrationPackage).append(".io.").append(baseName)
.append(mci ? "_I;\n" : "HttpRequest;\n")
.append("import ").append(integrationPackage).append(".io.").append(baseName)
.append(mci ? "_O;\n" : "HttpResponse;\n");
fields.append(" private final ").append(baseName).append("Client ").append(clientVariable).append(";\n");
fields.append(" private final ").append(baseName).append("Converter ").append(converterVariable).append(";\n");
methods.append(" @Override\n public ").append(baseName).append("Response ").append(tool.methodName())
.append("(").append(baseName).append("Request req) {\n")
.append(" ").append(baseName).append("_I request = converter.to").append(baseName).append("Request(req);\n")
.append(" ").append(baseName).append("_O response = ").append(clientVariable).append(".call").append(baseName).append("(request);\n")
.append(" ").append(baseName).append("Response toolResponse = converter.to").append(baseName).append("Response(response);\n")
.append(" ").append(baseName).append(mci ? "_I" : "HttpRequest").append(" request = ").append(converterVariable).append(".toRequest(req);\n")
.append(" ").append(baseName).append(mci ? "_O" : "HttpResponse").append(" response = ").append(clientVariable).append(mci ? ".call" + baseName + "(request);\n" : ".call(request, " + baseName + "HttpResponse.class);\n")
.append(" ").append(baseName).append("Response toolResponse = ").append(converterVariable).append(".toResponse(response);\n")
.append(" if (toolResponse == null) toolResponse = new ").append(baseName).append("Response();\n")
.append(" toolResponse.setResultCode(\"SUCCESS\");\n")
.append(" return toolResponse;\n }\n\n");
}
return "package " + bizPackage + ".usecase.impl;\n\n"
+ "import " + bizPackage + ".converter." + useCaseBaseName + "Converter;\n"
+ "import " + bizPackage + ".usecase." + useCaseBaseName + "UseCase;\n"
+ "import lombok.RequiredArgsConstructor;\nimport org.springframework.stereotype.Service;\n" + imports
+ "\n@Service\n@RequiredArgsConstructor\npublic class " + useCaseBaseName + "UseCaseImpl implements " + useCaseBaseName + "UseCase {\n\n"
+ " private final " + useCaseBaseName + "Converter converter;\n" + fields + "\n" + methods + "}\n";
+ fields + "\n" + methods + "}\n";
}
private static String groupedConverterContent(String bizPackage, String useCaseBaseName,
List<ToolMethodDefinition> tools) {
StringBuilder imports = new StringBuilder();
StringBuilder methods = new StringBuilder();
return "package " + bizPackage + ".converter;\n\n/** Per-Tool converters are generated beside this compatibility marker. */\n"
+ "public interface " + useCaseBaseName + "Converter {\n}\n";
}
private static String groupedMciConverterContent(String bizPackage, String baseName, String ioPackage) {
return "package " + bizPackage + ".converter;\n\n"
+ "import " + bizPackage + ".dto." + baseName + "Request;\n"
+ "import " + bizPackage + ".dto." + baseName + "Response;\n"
+ "import " + ioPackage + ".io." + baseName + "_I;\n"
+ "import " + ioPackage + ".io." + baseName + "_O;\n"
+ "import org.mapstruct.Mapper;\nimport org.mapstruct.ReportingPolicy;\n\n"
+ "@Mapper(componentModel = \"spring\", unmappedTargetPolicy = ReportingPolicy.IGNORE)\n"
+ "public interface " + baseName + "Converter {\n"
+ " " + baseName + "_I toRequest(" + baseName + "Request request);\n"
+ " " + baseName + "Response toResponse(" + baseName + "_O response);\n}\n";
}
private static String groupedHttpConverterContent(String bizPackage, String baseName, String ioPackage) {
return "package " + bizPackage + ".converter;\n\n"
+ "import " + bizPackage + ".dto." + baseName + "Request;\n"
+ "import " + bizPackage + ".dto." + baseName + "Response;\n"
+ "import " + ioPackage + ".io." + baseName + "HttpRequest;\n"
+ "import " + ioPackage + ".io." + baseName + "HttpResponse;\n"
+ "import org.mapstruct.Mapper;\nimport org.mapstruct.ReportingPolicy;\n\n"
+ "@Mapper(componentModel = \"spring\", unmappedTargetPolicy = ReportingPolicy.IGNORE)\n"
+ "public interface " + baseName + "Converter {\n"
+ " " + baseName + "HttpRequest toRequest(" + baseName + "Request request);\n"
+ " " + baseName + "Response toResponse(" + baseName + "HttpResponse response);\n}\n";
}
private static void appendGroupedUseCaseSources(Path useCaseFile, Path useCaseImplFile, Path converterFile,
String bizPackage, String useCaseBaseName, String moduleName,
List<ToolMethodDefinition> tools) throws IOException {
if (!Files.exists(useCaseImplFile)) {
throw new IllegalArgumentException("UseCase implementation not found: " + useCaseImplFile);
}
String useCase = Files.readString(useCaseFile, StandardCharsets.UTF_8);
String implementation = Files.readString(useCaseImplFile, StandardCharsets.UTF_8);
for (ToolMethodDefinition tool : tools) {
String baseName = toPascalCase(tool.baseName());
String code = tool.clientSystemCode().toLowerCase(Locale.ROOT);
imports.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Request;\n")
.append("import ").append(bizPackage).append(".dto.").append(baseName).append("Response;\n")
.append("import ").append(BASE_PACKAGE).append(".infra.itrf.mci.").append(code).append(".io.").append(baseName).append("_I;\n")
.append("import ").append(BASE_PACKAGE).append(".infra.itrf.mci.").append(code).append(".io.").append(baseName).append("_O;\n");
methods.append(" ").append(baseName).append("_I to").append(baseName).append("Request(").append(baseName).append("Request request);\n")
.append(" ").append(baseName).append("Response to").append(baseName).append("Response(").append(baseName).append("_O response);\n\n");
String methodName = tool.methodName();
String toolName = toToolName(moduleName, tool.group(), baseName);
if (useCase.matches("(?s).*\\b" + java.util.regex.Pattern.quote(methodName) + "\\s*\\(.*")
|| useCase.contains("name = \"" + toolName + "\"")) {
throw new IllegalArgumentException("Tool method or MCP Tool name already exists: " + methodName);
}
boolean mci = "MCI".equalsIgnoreCase(tool.routingType());
String integrationPackage = BASE_PACKAGE + (mci ? ".infra.itrf.mci." + tool.clientSystemCode().toLowerCase(Locale.ROOT)
: ".infra.itrf.http." + toPackageSegment(tool.httpApiName()));
String requestType = baseName + "Request";
String responseType = baseName + "Response";
String requestIo = baseName + (mci ? "_I" : "HttpRequest");
String responseIo = baseName + (mci ? "_O" : "HttpResponse");
String clientVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Client";
String converterVariable = Character.toLowerCase(baseName.charAt(0)) + baseName.substring(1) + "Converter";
useCase = addImport(useCase, "import " + bizPackage + ".dto." + requestType + ";") ;
useCase = addImport(useCase, "import " + bizPackage + ".dto." + responseType + ";") ;
String declaration = "\n @McpTool(name = \"" + toolName + "\", title = \"" + javaText(option(tool.title(), baseName))
+ "\", description = \"" + javaText(option(tool.description(), "")) + "\")\n"
+ " @ToolHint(register = " + tool.register() + ", categoryKey = \"" + tool.group().toLowerCase(Locale.ROOT)
+ "\", mappingId = \"" + javaText(option(tool.interfaceId(), tool.httpApiName())) + "\")\n"
+ " " + responseType + " " + methodName + "(" + requestType + " req);\n";
useCase = insertBeforeLastBrace(useCase, declaration);
implementation = addImport(implementation, "import " + bizPackage + ".dto." + requestType + ";");
implementation = addImport(implementation, "import " + bizPackage + ".dto." + responseType + ";");
implementation = addImport(implementation, "import " + bizPackage + ".converter." + baseName + "Converter;");
implementation = addImport(implementation, "import " + integrationPackage + "." + baseName + "Client;");
implementation = addImport(implementation, "import " + integrationPackage + ".io." + requestIo + ";");
implementation = addImport(implementation, "import " + integrationPackage + ".io." + responseIo + ";");
implementation = insertConstructorField(implementation, " private final " + baseName + "Client " + clientVariable + ";");
implementation = insertConstructorField(implementation, " private final " + baseName + "Converter " + converterVariable + ";");
String call = mci
? clientVariable + ".call" + baseName + "(request)"
: clientVariable + ".call(request, " + responseIo + ".class)";
String method = "\n @Override\n public " + responseType + " " + methodName + "(" + requestType + " req) {\n"
+ " " + requestIo + " request = " + converterVariable + ".toRequest(req);\n"
+ " " + responseIo + " response = " + call + ";\n"
+ " " + responseType + " toolResponse = " + converterVariable + ".toResponse(response);\n"
+ " if (toolResponse == null) toolResponse = new " + responseType + "();\n"
+ " toolResponse.setResultCode(\"SUCCESS\");\n"
+ " return toolResponse;\n }\n";
implementation = insertBeforeLastBrace(implementation, method);
}
return "package " + bizPackage + ".converter;\n\nimport org.mapstruct.Mapper;\nimport org.mapstruct.ReportingPolicy;\n"
+ imports + "\n@Mapper(componentModel = \"spring\", unmappedTargetPolicy = ReportingPolicy.IGNORE)\n"
+ "public interface " + useCaseBaseName + "Converter {\n\n" + methods + "}\n";
writeUtf8(useCaseFile, useCase);
writeUtf8(useCaseImplFile, implementation);
if (!Files.exists(converterFile)) {
writeUtf8(converterFile, groupedConverterContent(bizPackage, useCaseBaseName, tools));
}
}
private static String addImport(String content, String importLine) {
if (content.contains(importLine)) return content;
int lastImport = content.lastIndexOf("import ");
if (lastImport < 0) {
int packageEnd = content.indexOf(';');
return content.substring(0, packageEnd + 1) + "\n\n" + importLine + content.substring(packageEnd + 1);
}
int lineEnd = content.indexOf('\n', lastImport);
return content.substring(0, lineEnd + 1) + importLine + "\n" + content.substring(lineEnd + 1);
}
private static String insertConstructorField(String content, String field) {
if (content.contains(field)) return content;
int constructorField = content.indexOf("private final ");
if (constructorField < 0) return insertBeforeLastBrace(content, "\n" + field + "\n");
int lineEnd = content.indexOf('\n', constructorField);
return content.substring(0, lineEnd + 1) + field + "\n" + content.substring(lineEnd + 1);
}
private static String insertBeforeLastBrace(String content, String addition) {
int brace = content.lastIndexOf('}');
if (brace < 0) throw new IllegalArgumentException("Java source closing brace not found.");
return content.substring(0, brace) + addition + content.substring(brace);
}
private static String groupedMciClientContent(String ioPackage, String baseName, String interfaceId) {
@@ -1325,7 +1463,7 @@ public class ToolScaffolder {
}
private static void ensureLocalHttpApiConfiguration(Path projectRoot, String httpApiName, String toolName) throws IOException {
Path localConfigPath = projectRoot.resolve("dap-was-lib/src/main/resources/glow/application-glow-local.yml");
Path localConfigPath = projectRoot.resolve("src/main/resources/glow/application-glow-local.yml");
Files.createDirectories(localConfigPath.getParent());
String existing = Files.exists(localConfigPath) ? Files.readString(localConfigPath, StandardCharsets.UTF_8) : "";
if (java.util.regex.Pattern.compile("(?m)^\\s*-\\s+name:\\s*"
@@ -1396,8 +1534,8 @@ public class ToolScaffolder {
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class %s {
%s}
""".formatted(packageName, listImport, className, body);
%s%s}
""".formatted(packageName, listImport, className, body, innerObjectListClasses(fields));
}
private static String mciIoContent(String packageSuffix, String className, List<FieldDefinition> fields,
@@ -1412,8 +1550,9 @@ public class ToolScaffolder {
@Data
public class %s {
%s}
""".formatted(BASE_PACKAGE, packageSuffix, listImport, className, fieldLines(fields, Set.of(), className));
%s%s}
""".formatted(BASE_PACKAGE, packageSuffix, listImport, className, fieldLines(fields, Set.of(), className),
innerObjectListClasses(fields));
}
private static boolean hasListField(List<FieldDefinition> fields) {
@@ -1465,14 +1604,9 @@ public class ToolScaffolder {
}
""".formatted(packageName, enumName, constants, enumName, enumName, enumName));
}
if ("List".equals(field.type()) && "Object".equals(field.itemType())) {
List<FieldDefinition> itemFields = field.itemFields() == null ? List.of() : field.itemFields();
if (itemFields.isEmpty()) {
throw new IllegalArgumentException("Object List field needs item fields: " + field.name());
}
String itemName = listItemClassName(ownerClass, field);
writeUtf8(directory.resolve(itemName + ".java"), dtoContent(packageName, itemName, itemFields, "", "", true));
writeStructuredFieldTypes(directory, packageName, itemName, itemFields);
if ("List".equals(field.type()) && "Object".equals(field.itemType())
&& (field.itemFields() == null || field.itemFields().isEmpty())) {
throw new IllegalArgumentException("Object List field needs item fields: " + field.name());
}
}
}
@@ -1483,7 +1617,29 @@ public class ToolScaffolder {
}
private static String listItemClassName(String ownerClass, FieldDefinition field) {
return ownerClass + toPascalCase(field.name()) + "Item";
return toPascalCase(field.name()) + "Item";
}
private static String innerObjectListClasses(List<FieldDefinition> fields) {
StringBuilder source = new StringBuilder();
Set<String> generated = new LinkedHashSet<>();
for (FieldDefinition field : fields == null ? List.<FieldDefinition>of() : fields) {
if (field == null || !"List".equals(field.type()) || !"Object".equals(field.itemType())
|| field.name() == null || field.name().isBlank()) {
continue;
}
String itemName = listItemClassName("", field);
if (!generated.add(itemName)) continue;
List<FieldDefinition> itemFields = field.itemFields() == null ? List.of() : field.itemFields();
if (itemFields.isEmpty()) {
throw new IllegalArgumentException("Object List field needs item fields: " + field.name());
}
source.append("\n @Data\n public static class ").append(itemName).append(" {\n")
.append(fieldLines(itemFields, Set.of(), itemName))
.append(innerObjectListClasses(itemFields))
.append(" }\n");
}
return source.toString();
}
private static String httpUseCaseImplContent(String bizPackage, String baseName, String httpPackage,

View File

@@ -10,20 +10,6 @@ import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
//@Schema(description = "응답 에러 객체. 성공 케이스일 경우 null. 실제 에러가 발생할 경우에만 예외명, 예외 메시지 필드 세팅 예정.")
/**
* @package io.shinhanlife.glow
* @className BaseException
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
public class BaseException {
// @Schema(description = "Error 코드 Meta 참조 운영. (예) 20001, 50001 등", shinhanlife = "20001")
@@ -40,4 +26,4 @@ public class BaseException {
@Builder.Default
String exceptionDetail = "";
}
}

View File

@@ -5,20 +5,6 @@ import lombok.Builder;
import lombok.Getter;
import lombok.ToString;
/**
* @package io.shinhanlife.glow
* @className BaseResponse
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
@ToString
@Getter
@Builder
@@ -36,4 +22,4 @@ public class BaseResponse<T> {
private BaseException error;
}
}

View File

@@ -1,20 +1,61 @@
package io.shinhanlife.glow;
/**
* @package io.shinhanlife.glow
* @className BizException
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
* 업무 예외.
*
* <p>두 가지 방식으로 쓸 수 있다.</p>
* <ol>
* <li><b>메시지코드 방식(권장)</b> — {@code throw new BizException("DAH00004", "사번")}<br>
* 통합메시지(ZT_UNFC_MSG)에서 문구를 찾아 {0},{1}.. 을 인자로 치환해 응답한다.
* 문구가 화면·서버 한곳(관리 화면)에서 관리되고, 다국어 확장도 여기서 처리된다.</li>
* <li><b>문구 직접 방식(기존 호환)</b> — {@code throw new BizException("사번은 필수입니다.")}<br>
* 메시지코드로 해석되지 않으면 문구 그대로 응답한다.</li>
* </ol>
*
* <p>변환은 {@code common/config/GlobalExceptionHandler} 가 수행한다.
* 메시지코드 여부는 코드 형식(영문 대문자+숫자 8자리)으로 판별한다.</p>
*/
public class BizException extends RuntimeException {
public BizException(String s) {
/** 통합메시지코드 (문구 직접 방식이면 null) */
private final String msgCd;
/** 메시지 치환 인자 */
private final Object[] msgArgs;
/**
* 문구를 직접 지정하거나, 메시지코드만 던진다.
*
* @param messageOrCode 메시지 문구 또는 통합메시지코드
*/
public BizException(String messageOrCode) {
super(messageOrCode);
this.msgCd = isMessageCode(messageOrCode) ? messageOrCode : null;
this.msgArgs = new Object[0];
}
}
/**
* 메시지코드 + 치환 인자.
*
* @param msgCd 통합메시지코드 (예: DAH00004)
* @param msgArgs {0},{1}.. 에 순서대로 치환될 인자
*/
public BizException(String msgCd, Object... msgArgs) {
super(msgCd);
this.msgCd = msgCd;
this.msgArgs = msgArgs == null ? new Object[0] : msgArgs;
}
public String getMsgCd() {
return msgCd;
}
public Object[] getMsgArgs() {
return msgArgs;
}
/** 통합메시지코드 형식인지 — 영문 대문자 3자리 + 숫자 5자리 (예: DAH00001) */
private static boolean isMessageCode(String value) {
return value != null && value.matches("^[A-Z]{3}\\d{5}$");
}
}

View File

@@ -1,20 +1,5 @@
package io.shinhanlife.glow;
/**
* @package io.shinhanlife.glow
* @className GlowAppServiceId
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
import java.lang.annotation.*;
@Target(ElementType.METHOD)

View File

@@ -1,20 +1,5 @@
package io.shinhanlife.glow;
/**
* @package io.shinhanlife.glow
* @className GlowControllerId
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
public @interface GlowControllerId {
String value();
}

View File

@@ -1,20 +1,5 @@
package io.shinhanlife.glow;
/**
* @package io.shinhanlife.glow
* @className GlowIndexPaging
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
import java.lang.annotation.*;
@Target(ElementType.METHOD)

View File

@@ -9,21 +9,7 @@ public @interface GlowLogTarget {
Target[] value() default {};
/**
* @package io.shinhanlife.glow
* @className Target
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
enum Target {
FILE, CONSOLE
}
}
}

View File

@@ -5,20 +5,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
/**
* @package io.shinhanlife.glow
* @className GlowLogger
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
@Component
@Scope("prototype")
public class GlowLogger {

View File

@@ -1,20 +1,5 @@
package io.shinhanlife.glow;
/**
* @package io.shinhanlife.glow
* @className GlowMybatisMapper
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Component;

View File

@@ -1,20 +1,5 @@
package io.shinhanlife.glow;
/**
* @package io.shinhanlife.glow
* @className GlowServiceGroupId
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
public @interface GlowServiceGroupId {
String value();

View File

@@ -1,23 +1,7 @@
package io.shinhanlife.glow;
/**
* @package io.shinhanlife.glow
* @className GlowTrgmField
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
import java.lang.annotation.*;
@Deprecated(forRemoval = false)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented

View File

@@ -2,7 +2,6 @@ package io.shinhanlife.glow;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.shinhanlife.glow.communication.annotation.GlowTrgmField;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -11,20 +10,6 @@ import org.apache.ibatis.session.RowBounds;
import java.io.Serial;
import java.io.Serializable;
/**
* @package io.shinhanlife.glow
* @className PageInfo
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
@@ -35,25 +20,25 @@ public class PageInfo extends RowBounds implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 페이지번호 ( 입력값 )
* 페이지번호 (입력값)
*/
@GlowTrgmField(order = 1, length = 5, description = "페이지번호")
private int pageNo;
/**
* 페이지 데이터 건수 ( 열 건수, 입력값 )
* 페이지 데이터 건수 (열 건수, 입력값)
*/
@GlowTrgmField(order = 2, length = 5, description = "페이지데이터건수")
private int pageDataCc;
/**
* 총페이지 수 ( 리턴값 )
* 총페이지 수 (리턴값)
*/
@GlowTrgmField(order = 3, length = 10, description = "총페이지수")
private int totaPageCn;
/**
* 총 페이지 데이터 건수 ( 리턴값 )
* 총 페이지 데이터 건수 (리턴값)
*/
@GlowTrgmField(order = 4, length = 10, description = "총페이지데이터건수")
private int totaPageDataCc;
@@ -80,4 +65,4 @@ public class PageInfo extends RowBounds implements Serializable {
return super.getLimit();
}
}
}

View File

@@ -4,20 +4,6 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
/**
* @package io.shinhanlife.glow
* @className ResponseCode
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
@Getter
@RequiredArgsConstructor
public enum ResponseCode {
@@ -42,4 +28,4 @@ public enum ResponseCode {
private final HttpStatus status;
private final String message;
}
}

View File

@@ -3,20 +3,6 @@ package io.shinhanlife.glow;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
/**
* @package io.shinhanlife.glow
* @className ResponseUtil
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
public final class ResponseUtil {
private ResponseUtil() {
@@ -122,4 +108,4 @@ public final class ResponseUtil {
);
}
}
}

View File

@@ -2,30 +2,11 @@ package io.shinhanlife.glow.db.dto;
import lombok.Getter;
import lombok.Setter;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import java.util.Date;
/**
* @package io.shinhanlife.glow.db.dto
* @className AuditInfo
* @description AX HUB 시스템 처리 클래스
* @author 0986406
* @create 2026.09.01
* <pre>
* ---------- 개정이력 ----------
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2026.09.01 0986406 최초생성
*
* </pre>
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AuditInfo {
private Date systRgiDt; // 시스템등록일시
private String systRgiPrafNo; // 시스템등록인사번호
@@ -37,4 +18,4 @@ public class AuditInfo {
private String systChgOgnzNo; // 시스템변경조직번호
private String systChgSystCd; // 시스템변경시스템코드
private String systChgPrgrId; // 시스템변경프로그램ID
}
}

View File

@@ -0,0 +1,11 @@
package io.shinhanlife.glow.db.typehandler;
/**
* glow 프레임워크 스텁 (실제 라이브러리가 없는 로컬 개발 환경용 더미).
* 코드값을 갖는 enum이 공통으로 구현하는 인터페이스 — {@link CodeEnumTypeHandler}가 이 getCode()로
* DB 컬럼(String)과 enum 상수를 상호 변환한다.
*/
public interface CodeEnum {
String getCode();
}

View File

@@ -0,0 +1,59 @@
package io.shinhanlife.glow.db.typehandler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* glow 프레임워크 스텁 (실제 라이브러리가 없는 로컬 개발 환경용 더미).
* {@link CodeEnum}을 구현하는 코드 enum과 DB 문자열 컬럼(코드값)을 상호 변환하는 MyBatis TypeHandler
* 공통 베이스. common/enums/type의 {@code {ClassName}TypeHandler}는 모두 이 클래스를 상속하고,
* 생성자에서 자신의 enum 타입을 super(...)로 넘기기만 한다.
*/
public abstract class CodeEnumTypeHandler<E extends Enum<E> & CodeEnum> extends BaseTypeHandler<E> {
private final Class<E> type;
protected CodeEnumTypeHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, parameter.getCode());
}
@Override
public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
return toEnum(rs.getString(columnName));
}
@Override
public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return toEnum(rs.getString(columnIndex));
}
@Override
public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return toEnum(cs.getString(columnIndex));
}
private E toEnum(String code) {
if (code == null) {
return null;
}
for (E constant : type.getEnumConstants()) {
if (constant.getCode().equals(code)) {
return constant;
}
}
throw new IllegalArgumentException("알 수 없는 코드 [" + code + "] - " + type.getName());
}
}