Skip to content

Commit e7b3888

Browse files
committed
not looking good, some more work on #1558
this time simlifying the detach routine to be less prone to graal issues not able to avoid the synchronize for recurseAndAttach() had to add a coupld more but thankfully only for the callonce / callsingle flows but still saw a failure once in a while
1 parent b12a4ff commit e7b3888

File tree

2 files changed

+77
-64
lines changed

2 files changed

+77
-64
lines changed

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

+20-12
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,7 @@ protected void recurseAndAttach(Object o) {
11051105

11061106
private Object recurseAndAttach(Object o, Set<Object> seen) {
11071107
if (o instanceof Value) {
1108-
Value value = (Value) o;
1108+
Value value = Value.asValue(o);
11091109
try {
11101110
if (value.canExecute()) {
11111111
if (value.isMetaObject()) { // js function
@@ -1114,7 +1114,7 @@ private Object recurseAndAttach(Object o, Set<Object> seen) {
11141114
return new JsExecutable(value);
11151115
}
11161116
} else { // anything else, including java-type references
1117-
return Value.asValue(value);
1117+
return value;
11181118
}
11191119
} catch (Exception e) {
11201120
logger.warn("[attach] failed to attach js value: {}", e.getMessage());
@@ -1152,17 +1152,19 @@ private Object recurseAndAttach(Object o, Set<Object> seen) {
11521152
}
11531153
}
11541154

1155+
// called only by result processing of callonce / callSingle
11551156
protected Object recurseAndAttachAndDeepClone(Object o) {
11561157
Set<Object> seen = Collections.newSetFromMap(new IdentityHashMap());
1157-
return recurseAndAttachAndDeepClone(o, seen);
1158+
synchronized (runtime.featureRuntime.suite) {
1159+
return recurseAndAttachAndDeepClone(o, seen);
1160+
}
11581161
}
11591162

11601163
private Object recurseAndAttachAndDeepClone(Object o, Set<Object> seen) {
11611164
if (o instanceof Value) {
11621165
// will happen only for java "class" and java functions (static methods)
1163-
Value value = (Value) o;
11641166
try {
1165-
return Value.asValue(value);
1167+
return Value.asValue(o);
11661168
} catch (Exception e) {
11671169
logger.warn("[attach deep] failed to attach graal value: {}", e.getMessage());
11681170
return null;
@@ -1175,7 +1177,7 @@ private Object recurseAndAttachAndDeepClone(Object o, Set<Object> seen) {
11751177
if (seen.add(o)) {
11761178
List list = (List) o;
11771179
List copy = new ArrayList(list.size());
1178-
list.forEach(v -> copy.add(recurseAndAttachAndDeepClone(v)));
1180+
list.forEach(v -> copy.add(recurseAndAttachAndDeepClone(v, seen)));
11791181
return copy;
11801182
} else {
11811183
return o;
@@ -1184,7 +1186,7 @@ private Object recurseAndAttachAndDeepClone(Object o, Set<Object> seen) {
11841186
if (seen.add(o)) {
11851187
Map<String, Object> map = (Map) o;
11861188
Map<String, Object> copy = new LinkedHashMap(map.size());
1187-
map.forEach((k, v) -> copy.put(k, recurseAndAttachAndDeepClone(v)));
1189+
map.forEach((k, v) -> copy.put(k, recurseAndAttachAndDeepClone(v, seen)));
11881190
return copy;
11891191
} else {
11901192
return o;
@@ -1204,12 +1206,18 @@ protected Object recurseAndDetachAndDeepClone(Object o) {
12041206

12051207
private Object recurseAndDetachAndDeepClone(Object o, Set<Object> seen) {
12061208
if (o instanceof Value) {
1207-
Value value = (Value) o;
1208-
if (!value.isHostObject() && value.canExecute()) {
1209-
return new JsFunction(value);
1210-
}
1209+
Value value = Value.asValue(o);
12111210
try {
1212-
o = JsValue.toJava(value);
1211+
if (value.canExecute()) {
1212+
if (value.isMetaObject()) { // js function
1213+
o = new JsFunction(value);
1214+
} else { // java function
1215+
o = new JsExecutable(value);
1216+
}
1217+
} else {
1218+
// everything else including java-type references that do not need special attach handling
1219+
o = value;
1220+
}
12131221
} catch (Exception e) {
12141222
logger.warn("[detach] unsupported value in callonce / callSingle: {}", e.getMessage());
12151223
return null;

karate-core/src/main/java/com/intuit/karate/graal/JsValue.java

+57-52
Original file line numberDiff line numberDiff line change
@@ -62,62 +62,67 @@ public static enum Type {
6262

6363
public JsValue(Value v) {
6464
this.original = v;
65-
if (v.isNull()) { // apparently this can be a "host object" as well !
66-
value = null;
67-
type = Type.NULL;
68-
} else if (v.isProxyObject()) {
69-
Object o = v.asProxyObject();
70-
if (o instanceof JsXml) {
71-
value = ((JsXml) o).getNode();
72-
type = Type.XML;
73-
} else if (o instanceof JsMap) {
74-
value = ((JsMap) o).getMap();
75-
type = Type.OBJECT;
76-
} else if (o instanceof JsList) {
77-
value = ((JsList) o).getList();
65+
try {
66+
if (v.isNull()) { // apparently this can be a "host object" as well !
67+
value = null;
68+
type = Type.NULL;
69+
} else if (v.isProxyObject()) {
70+
Object o = v.asProxyObject();
71+
if (o instanceof JsXml) {
72+
value = ((JsXml) o).getNode();
73+
type = Type.XML;
74+
} else if (o instanceof JsMap) {
75+
value = ((JsMap) o).getMap();
76+
type = Type.OBJECT;
77+
} else if (o instanceof JsList) {
78+
value = ((JsList) o).getList();
79+
type = Type.ARRAY;
80+
} else if (o instanceof JsExecutable) {
81+
value = (JsExecutable) o;
82+
type = Type.FUNCTION;
83+
} else { // e.g. custom bridge, e.g. Request
84+
value = v.as(Object.class);
85+
type = Type.OTHER;
86+
}
87+
} else if (v.isHostObject()) { // java object
88+
if (v.isMetaObject()) { // java.lang.Class !
89+
value = v; // special case, keep around as graal value
90+
} else {
91+
value = v.asHostObject();
92+
}
93+
type = Type.OTHER;
94+
} else if (v.canExecute()) {
95+
if (v.isMetaObject()) { // js function
96+
value = v; // special case, keep around as graal value
97+
} else { // java function reference
98+
value = new JsExecutable(v);
99+
}
100+
type = Type.FUNCTION;
101+
} else if (v.hasArrayElements()) {
102+
int size = (int) v.getArraySize();
103+
List list = new ArrayList(size);
104+
for (int i = 0; i < size; i++) {
105+
Value child = v.getArrayElement(i);
106+
list.add(new JsValue(child).value);
107+
}
108+
value = list;
78109
type = Type.ARRAY;
79-
} else if (o instanceof JsExecutable) {
80-
value = (JsExecutable) o;
81-
type = Type.FUNCTION;
82-
} else { // e.g. custom bridge, e.g. Request
110+
} else if (v.hasMembers()) {
111+
Set<String> keys = v.getMemberKeys();
112+
Map<String, Object> map = new LinkedHashMap(keys.size());
113+
for (String key : keys) {
114+
Value child = v.getMember(key);
115+
map.put(key, new JsValue(child).value);
116+
}
117+
value = map;
118+
type = Type.OBJECT;
119+
} else {
83120
value = v.as(Object.class);
84121
type = Type.OTHER;
85122
}
86-
} else if (v.isHostObject()) { // java object
87-
if (v.isMetaObject()) { // java.lang.Class !
88-
value = v; // special case, keep around as graal value
89-
} else {
90-
value = v.asHostObject();
91-
}
92-
type = Type.OTHER;
93-
} else if (v.canExecute()) {
94-
if (v.isMetaObject()) { // js function
95-
value = v; // special case, keep around as graal value
96-
} else { // java function reference
97-
value = new JsExecutable(v);
98-
}
99-
type = Type.FUNCTION;
100-
} else if (v.hasArrayElements()) {
101-
int size = (int) v.getArraySize();
102-
List list = new ArrayList(size);
103-
for (int i = 0; i < size; i++) {
104-
Value child = v.getArrayElement(i);
105-
list.add(new JsValue(child).value);
106-
}
107-
value = list;
108-
type = Type.ARRAY;
109-
} else if (v.hasMembers()) {
110-
Set<String> keys = v.getMemberKeys();
111-
Map<String, Object> map = new LinkedHashMap(keys.size());
112-
for (String key : keys) {
113-
Value child = v.getMember(key);
114-
map.put(key, new JsValue(child).value);
115-
}
116-
value = map;
117-
type = Type.OBJECT;
118-
} else {
119-
value = v.as(Object.class);
120-
type = Type.OTHER;
123+
} catch (Exception e) {
124+
logger.debug("js conversion failed", e);
125+
throw e;
121126
}
122127
}
123128

0 commit comments

Comments
 (0)