Skip to content

Commit 5a7c496

Browse files
committed
a bit of re-factoring of attach routine #1558
1 parent 4b56abb commit 5a7c496

File tree

1 file changed

+51
-40
lines changed

1 file changed

+51
-40
lines changed

karate-core/src/main/java/com/intuit/karate/core/ScenarioEngine.java

+51-40
Original file line numberDiff line numberDiff line change
@@ -1022,13 +1022,17 @@ public void init() { // not in constructor because it has to be on Runnable.run(
10221022
runtime.magicVariables.forEach((k, v) -> {
10231023
// even hidden variables may need pre-processing
10241024
// for e.g. the __arg may contain functions that originated in a different js context
1025-
Object o = recurseAndAttach(k, v, seen);
1026-
if (o == null) {
1027-
o = v;
1028-
}
1029-
JS.put(k, o);
1025+
AttachResult ar = recurseAndAttach(k, v, seen);
1026+
JS.put(k, ar.value);
1027+
});
1028+
// re-hydrate any functions from caller or background
1029+
vars.forEach((k, v) -> {
1030+
AttachResult ar = recurseAndAttach(k, v.getValue(), seen);
1031+
// note that we don't update the vars !
1032+
// if we do, any "bad" out-of-context values will crash the constructor of Variable
1033+
// it is possible the vars are detached / re-used later, so we kind of defer the inevitable
1034+
JS.put(k, ar.value);
10301035
});
1031-
attachVariables(seen); // re-hydrate any functions from caller or background
10321036
JS.put(KARATE, bridge);
10331037
JS.put(READ, readFunction);
10341038
HttpClient client = runtime.featureRuntime.suite.clientFactory.create(this);
@@ -1049,22 +1053,6 @@ public void init() { // not in constructor because it has to be on Runnable.run(
10491053
}
10501054
}
10511055

1052-
private void attachVariables(Set<Object> seen) {
1053-
vars.forEach((k, v) -> {
1054-
Object o = recurseAndAttach(k, v.getValue(), seen);
1055-
if (o == null) {
1056-
o = v.getValue();
1057-
} else {
1058-
try {
1059-
vars.put(k, new Variable(o));
1060-
} catch (Exception e) {
1061-
logger.debug("[*** attach variables ***] ignoring non-json value: '{}' - {}", k, e.getMessage());
1062-
}
1063-
}
1064-
JS.put(k, o);
1065-
});
1066-
}
1067-
10681056
protected Map<String, Variable> detachVariables() {
10691057
Set<Object> seen = Collections.newSetFromMap(new IdentityHashMap());
10701058
Map<String, Variable> detached = new HashMap(vars.size());
@@ -1075,53 +1063,76 @@ protected Map<String, Variable> detachVariables() {
10751063
return detached;
10761064
}
10771065

1078-
private Object recurseAndAttach(String name, Object o, Set<Object> seen) {
1066+
private static class AttachResult {
1067+
1068+
final Object value;
1069+
final boolean dirty;
1070+
1071+
static final AttachResult NULL = new AttachResult(null, true);
1072+
1073+
AttachResult(Object value, boolean dirty) {
1074+
this.value = value;
1075+
this.dirty = dirty;
1076+
}
1077+
1078+
static AttachResult dirty(Object value) {
1079+
return new AttachResult(value, true);
1080+
}
1081+
1082+
static AttachResult clean(Object value) {
1083+
return new AttachResult(value, false);
1084+
}
1085+
1086+
}
1087+
1088+
private AttachResult recurseAndAttach(String name, Object o, Set<Object> seen) {
10791089
if (o instanceof Value) {
1090+
Value value = Value.asValue(o);
10801091
try {
1081-
Value value = Value.asValue(o);
10821092
if (value.canExecute() && value.isMetaObject()) { // js function
1083-
return attach(value);
1093+
return AttachResult.dirty(attach(value));
10841094
} else { // anything else, including java functions and java-type references
1085-
return value;
1095+
return AttachResult.dirty(value);
10861096
}
10871097
} catch (Exception e) {
10881098
logger.warn("[*** attach ***] ignoring non-json value: '{}' - {}", name, e.getMessage());
1089-
return null;
1099+
// here we sweep things under the carpet and hope that graal does not notice !
1100+
return AttachResult.dirty(value);
10901101
}
10911102
} else if (o instanceof JsFunction) {
10921103
JsFunction jf = (JsFunction) o;
10931104
try {
1094-
return attachSource(jf.source);
1105+
return AttachResult.dirty(attachSource(jf.source));
10951106
} catch (Exception e) {
10961107
logger.warn("[*** attach ***] ignoring js-function: '{}' - {}", name, e.getMessage());
1097-
return null;
1098-
}
1108+
return AttachResult.NULL;
1109+
}
10991110
} else if (o instanceof List) {
11001111
if (seen.add(o)) {
11011112
List list = (List) o;
11021113
int count = list.size();
11031114
for (int i = 0; i < count; i++) {
11041115
Object child = list.get(i);
1105-
Object result = recurseAndAttach(name + "[" + i + "]", child, seen);
1106-
if (result != null) {
1107-
list.set(i, result);
1116+
AttachResult ar = recurseAndAttach(name + "[" + i + "]", child, seen);
1117+
if (ar.dirty) {
1118+
list.set(i, ar.value);
11081119
}
11091120
}
11101121
}
1111-
return null;
1122+
return AttachResult.clean(o);
11121123
} else if (o instanceof Map) {
11131124
if (seen.add(o)) {
11141125
Map<String, Object> map = (Map) o;
11151126
map.forEach((k, v) -> {
1116-
Object result = recurseAndAttach(name + "." + k, v, seen);
1117-
if (result != null) {
1118-
map.put(k, result);
1127+
AttachResult ar = recurseAndAttach(name + "." + k, v, seen);
1128+
if (ar.dirty) {
1129+
map.put(k, ar.value);
11191130
}
11201131
});
11211132
}
1122-
return null;
1133+
return AttachResult.clean(o);
11231134
} else {
1124-
return null;
1135+
return AttachResult.clean(o);
11251136
}
11261137
}
11271138

@@ -1146,7 +1157,7 @@ private Object recurseAndAttachAndDeepClone(String name, Object o, Set<Object> s
11461157
return attachSource(jf.source);
11471158
} catch (Exception e) {
11481159
logger.warn("[*** attach deep ***] ignoring js-function: '{}' - {}", name, e.getMessage());
1149-
return null;
1160+
return null;
11501161
}
11511162
} else if (o instanceof List) {
11521163
if (seen.add(o)) {

0 commit comments

Comments
 (0)