EZDATA 없는데, Ref필드에는 'ERP'로 되어 있는 경우, flat 전문 파싱 오류 처리

This commit is contained in:
curry772
2026-09-07 14:39:31 +09:00
parent 1bf2c78f03
commit 5e07100c3d
3 changed files with 101 additions and 52 deletions
@@ -294,7 +294,59 @@ public class StandardItem implements Serializable, Cloneable {
public void setHidden(boolean isHidden) {
this.isHidden = isHidden;
}
/**
* 조건부 블록의 refValue 와 실제 필드값을 비교한다.
* FlatReader / StandardMessageCoordinator 와 동일한 기준을 쓰기 위한 공용 판정 로직이다.
* - '!' 접두사 : NOT 조건 (예: !S → S가 아닌 경우)
* - '|' 구분자 : OR 조건 (예: NM|EM → NM 또는 EM인 경우)
* - '!' 와 '|' 조합 가능 (예: !NM|EM → NM도 EM도 아닌 경우)
*/
public static boolean matchRefCondition(String refValue, String actualValue) {
if(refValue == null) return false;
String expect = refValue;
boolean negate = expect.startsWith("!");
if(negate) {
expect = expect.substring(1);
}
String actual = (actualValue == null) ? null : actualValue.trim();
boolean matched = false;
String[] expectValues = expect.split("\\|");
for(int i=0; i<expectValues.length; i++) {
if(expectValues[i].equals(actual)) {
matched = true;
break;
}
}
return negate ? !matched : matched;
}
/**
* FLAT 직렬화 시 이 GROUP 블록의 바이트를 출력할지 판단한다.
* FlatReader.traverse() 의 GROUP 처리와 같은 기준을 쓰기 위한 것으로,
* ref 조건이 성립하면 size==0(전문에 블록이 없어 미활성) 이어도 레이아웃 기본값으로 출력한다.
* 조건이 성립하는데 출력하지 않으면, 파서는 블록이 있다고 보고 읽어 오프셋이 어긋난다.
*
* @param root 조건 평가 기준이 되는 최상위 메시지. null 이면 조건 평가 없이 기존 규칙만 적용
* @param parentActivated 조건 성립으로 활성화된 상위 GROUP 하위인지 여부
*/
protected boolean isFlatGroupActive(StandardMessage root, boolean parentActivated) {
if(isHidden) return false;
if(getSize() > 0) return true;
if(root != null
&& StringUtils.isNotBlank(getRefPath())
&& StringUtils.isNotBlank(getRefValue())
&& matchRefCondition(getRefValue(), root.findItemValue(getRefPath())) ) {
if(logger.isDebugEnabled()) {
logger.debug("@GROUP name={} ACTIVATED by ref condition({}=[{}]). size=0 이지만 FLAT 출력 대상"
, getName(), getRefPath(), getRefValue());
}
return true;
}
// 조건 성립으로 활성화된 상위 GROUP 하위의 무조건 블록은 함께 출력한다.
return parentActivated;
}
protected String toTypeValue(String svalue) {
if(svalue == null) return svalue;
@@ -1007,6 +1059,15 @@ public class StandardItem implements Serializable, Cloneable {
}
public int getBytesDataLength(String charset) {
return getBytesDataLength(charset, null, false);
}
/**
* @param root 조건부 블록(refPath/refValue) 평가 기준이 되는 최상위 메시지
* @param parentActivated 조건 성립으로 활성화된 상위 GROUP 하위인지 여부
* @see #isFlatGroupActive(StandardMessage, boolean)
*/
public int getBytesDataLength(String charset, StandardMessage root, boolean parentActivated) {
int totalSize = 0;
Iterator<String> keyIter = null;
try {
@@ -1016,24 +1077,26 @@ public class StandardItem implements Serializable, Cloneable {
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = childs.get(key);
totalSize +=item.getBytesDataLength(charset);
totalSize +=item.getBytesDataLength(charset, root, false);
}
break;
case StandardType.FIELD :
totalSize += getLength();
break;
case StandardType.GROUP :
// skip inactive/conditional group (size==0 means not activated)
if( getSize() == 0 ) {
// ref 조건이 성립하면 size==0 이어도 출력한다(FlatReader 와 동일 기준)
if( !isFlatGroupActive(root, parentActivated) ) {
break;
}
if (isHidden) break;
// 출력하는 GROUP 의 하위 무조건 블록은 함께 출력한다.
// FlatReader 는 이 블록을 조건 없이 읽으므로 빼면 오프셋이 어긋난다.
boolean childActivated = true;
keyIter = childs.keySet().iterator();
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = childs.get(key);
totalSize +=item.getBytesDataLength(charset);
}
totalSize +=item.getBytesDataLength(charset, root, childActivated);
}
break;
case StandardType.GRID :
if( getSize() == 0
@@ -1044,14 +1107,14 @@ public class StandardItem implements Serializable, Cloneable {
break;
}
if (isHidden) break;
for(int p=0; p<list.size(); p++) {
for(int p=0; p<list.size(); p++) {
LinkedHashMap<String , StandardItem> group = list.get(p);
keyIter = group.keySet().iterator();
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = group.get(key);
totalSize +=item.getBytesDataLength(charset);
}
totalSize +=item.getBytesDataLength(charset, root, false);
}
}
break;
case StandardType.FARRAY :
@@ -1086,8 +1149,17 @@ public class StandardItem implements Serializable, Cloneable {
return toByteArray(true, charset);
}
public byte[] toByteArray(boolean withBizData, String charset) {
return toByteArray(withBizData, charset, null, false);
}
/**
* @param root 조건부 블록(refPath/refValue) 평가 기준이 되는 최상위 메시지
* @param parentActivated 조건 성립으로 활성화된 상위 GROUP 하위인지 여부
* @see #isFlatGroupActive(StandardMessage, boolean)
*/
public byte[] toByteArray(boolean withBizData, String charset, StandardMessage root, boolean parentActivated) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Iterator<String> keyIter = null;
Iterator<String> keyIter = null;
// logger.debug("Encoding : {}", charset);
try {
switch(getType()) {
@@ -1096,7 +1168,7 @@ public class StandardItem implements Serializable, Cloneable {
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = childs.get(key);
bos.write(item.toByteArray(withBizData,charset)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101
bos.write(item.toByteArray(withBizData, charset, root, false)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101
}
break;
case StandardType.FIELD :
@@ -1118,17 +1190,19 @@ public class StandardItem implements Serializable, Cloneable {
}
break;
case StandardType.GROUP :
// skip inactive/conditional group (size==0 means not activated)
if( getSize() == 0 ) {
// ref 조건이 성립하면 size==0 이어도 출력한다(FlatReader 와 동일 기준)
if( !isFlatGroupActive(root, parentActivated) ) {
break;
}
if (isHidden) break;
// 출력하는 GROUP 의 하위 무조건 블록은 함께 출력한다.
// FlatReader 는 이 블록을 조건 없이 읽으므로 빼면 오프셋이 어긋난다.
boolean childActivated = true;
keyIter = childs.keySet().iterator();
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = childs.get(key);
bos.write(item.toByteArray(withBizData,charset)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101
}
bos.write(item.toByteArray(withBizData, charset, root, childActivated)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101
}
break;
case StandardType.GRID :
if( getSize() == 0
@@ -1139,14 +1213,14 @@ public class StandardItem implements Serializable, Cloneable {
break;
}
if (isHidden) break;
for(int p=0; p<list.size(); p++) {
for(int p=0; p<list.size(); p++) {
LinkedHashMap<String , StandardItem> group = list.get(p);
keyIter = group.keySet().iterator();
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = group.get(key);
bos.write(item.toByteArray(withBizData, charset)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101
}
bos.write(item.toByteArray(withBizData, charset, root, false)); //하위로 내려갈때 withBizDat 값이 없어져서 추가 jun's 20231101
}
}
break;
case StandardType.FARRAY :
@@ -461,7 +461,8 @@ public class StandardMessage extends StandardItem {
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = childs.get(key);
bos.write(item.toByteArray(withBizData, charset));
// this 를 root 로 넘겨 조건부 블록(refPath/refValue)을 평가하게 한다
bos.write(item.toByteArray(withBizData, charset, this, false));
}
return bos.toByteArray();
} catch(Exception e) {
@@ -490,7 +491,7 @@ public class StandardMessage extends StandardItem {
while(keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = childs.get(key);
totalSize +=item.getBytesDataLength(charset);
totalSize +=item.getBytesDataLength(charset, this, false);
}
return totalSize;
} catch(Exception e) {
@@ -516,7 +517,7 @@ public class StandardMessage extends StandardItem {
while (keyIter.hasNext()) {
String key = keyIter.next();
StandardItem item = find.childs.get(key);
totalSize += item.getBytesDataLength(this.bizDataCharset);
totalSize += item.getBytesDataLength(this.bizDataCharset, this, false);
}
return totalSize;
} catch (Exception e) {
@@ -121,24 +121,15 @@ public class FlatReader implements StandardReader {
logger.debug("@GROUP name={}, getRefPath={}, refItemValue=[{}], getRefValue=[{}]"
, currentItem.getName(), currentItem.getRefPath(), refItemValue, currentItem.getRefValue());
if(refItemValue != null) refItemValue = refItemValue.trim();
/*
* 값의 경우의수 NM,EM,""(blank)
* ! : NOT 조건 (예: !EM → EM이 아닌 경우)
* | : OR 조건 (예: NM|EM → NM 또는 EM인 경우)
* !와 | 조합 가능 (예: !NM|EM → NM도 아니고 EM도 아닌 경우)
* 판정 기준은 StandardItem.matchRefCondition 하나로 통일한다.
* (FLAT 직렬화 StandardItem.isFlatGroupActive 와 같은 기준이어야 오프셋이 어긋나지 않음)
*/
String refValue = currentItem.getRefValue();
boolean isNot = refValue.startsWith("!");
if (isNot) {
refValue = refValue.substring(1);
}
boolean matched = matchRefValue(refValue, refItemValue);
if (isNot) {
matched = !matched;
}
boolean matched = StandardItem.matchRefCondition(currentItem.getRefValue(), refItemValue);
if (!matched) {
logger.warn("@GROUP name={} SKIPPED.", currentItem.getName());
@@ -307,21 +298,4 @@ public class FlatReader implements StandardReader {
}
return refItemValue;
}
/**
* refValue와 refItemValue를 비교하여 일치 여부를 반환
* | 구분자로 OR 조건 지원 (예: "NM|EM" → "NM" 또는 "EM"과 일치하면 true)
*/
private boolean matchRefValue(String refValue, String refItemValue) {
if (refValue.contains("|")) {
String[] values = refValue.split("\\|");
for (String val : values) {
if (val.equals(refItemValue)) {
return true;
}
}
return false;
}
return refValue.equals(refItemValue);
}
}