Skip to content

Commit a1973a3

Browse files
domkunJervenBolleman
authored andcommitted
GH-4833: Copy triple structures to avoid infinite loops
The current implementation of the algorithm for the hierachical JSON-LD output changes references of the triples stored in `List`s and keeps adding these references to the output. This can leed to infinite loops when traversing the result. Making copies of the contained lists avoids this.
1 parent cdb38ad commit a1973a3

3 files changed

Lines changed: 83 additions & 8 deletions

File tree

core/rio/jsonld/src/main/java/org/eclipse/rdf4j/rio/jsonld/JSONLDHierarchicalProcessor.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,7 @@
1010
*******************************************************************************/
1111
package org.eclipse.rdf4j.rio.jsonld;
1212

13-
import java.util.ArrayList;
14-
import java.util.HashSet;
15-
import java.util.LinkedHashMap;
16-
import java.util.LinkedList;
17-
import java.util.List;
18-
import java.util.Map;
19-
import java.util.Set;
13+
import java.util.*;
2014
import java.util.stream.Collectors;
2115

2216
/**
@@ -127,7 +121,16 @@ private static Object expandContextInDepth(Object input) {
127121
if (graph.containsKey(objectsPredId) && !currentNode.get(ID).equals(objectsPredId)
128122
&& !currentTreeNode.hasPassedThrough(objectsPredId)) {
129123
children.add(objectsPredId);
130-
objectsPredSubjPairs.set(i, (Map<String, Object>) graph.get(objectsPredId));
124+
Map<String, Object> tuples = (Map<String, Object>) graph.get(objectsPredId);
125+
Map<String, Object> copiedTuples = tuples.entrySet().stream().map(tuple -> {
126+
Map.Entry<String, Object> entry = new AbstractMap.SimpleEntry<>(tuple);
127+
if (tuple.getValue() instanceof List) {
128+
List<Object> copy = new ArrayList<>((Collection<?>) tuple.getValue());
129+
entry.setValue(copy);
130+
}
131+
return entry;
132+
}).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
133+
objectsPredSubjPairs.set(i, copiedTuples);
131134
frontier.add(new TreeNode(objectsPredSubjPairs.get(i), currentTreeNode));
132135
}
133136
}

core/rio/jsonld/src/test/java/org/eclipse/rdf4j/rio/jsonld/JSONLDHierarchicalWriterTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,35 @@ public void testOrderDuplicatedChild() throws IOException {
299299
verifyOutput();
300300
}
301301

302+
/**
303+
*
304+
* @throws IOException
305+
* @see <a href="https://github.com/eclipse-rdf4j/rdf4j/issues/4833s">GH-4833</a>
306+
*/
307+
@Test
308+
public void testMultipleLoops() throws IOException {
309+
addStatement(vf.createIRI("sch:node1"), vf.createIRI("sch:pred1"), vf.createIRI("sch:node2"));
310+
311+
addStatement(vf.createIRI("sch:node2"), vf.createIRI("sch:pred2"), vf.createIRI("sch:node3"));
312+
addStatement(vf.createIRI("sch:node2"), vf.createIRI("sch:pred2"), vf.createIRI("sch:node4"));
313+
addStatement(vf.createIRI("sch:node2"), vf.createIRI("sch:pred2"), vf.createIRI("sch:node5"));
314+
315+
addStatement(vf.createIRI("sch:node2"), vf.createIRI("sch:pred3"), vf.createIRI("sch:node1"));
316+
317+
addStatement(vf.createIRI("sch:node3"), vf.createIRI("sch:pred4"), vf.createIRI("sch:node2"));
318+
addStatement(vf.createIRI("sch:node3"), vf.createIRI("sch:pred5"), vf.createIRI("sch:node6"));
319+
320+
addStatement(vf.createIRI("sch:node4"), vf.createIRI("sch:pred4"), vf.createIRI("sch:node2"));
321+
322+
addStatement(vf.createIRI("sch:node5"), vf.createIRI("sch:pred4"), vf.createIRI("sch:node2"));
323+
addStatement(vf.createIRI("sch:node5"), vf.createIRI("sch:pred5"), vf.createIRI("sch:node6"));
324+
325+
addStatement(vf.createIRI("sch:node6"), vf.createIRI("sch:pred6"), vf.createIRI("sch:node3"));
326+
327+
verifyOutput();
328+
329+
}
330+
302331
private void addStatement(Resource subject, IRI predicate, Value object, Resource context) {
303332
model.add(vf.createStatement(subject, predicate, object, context));
304333
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
[ {
2+
"@id" : "sch:node2",
3+
"sch:pred2" : [ {
4+
"@id" : "sch:node3",
5+
"sch:pred4" : [ {
6+
"@id" : "sch:node2"
7+
} ],
8+
"sch:pred5" : [ {
9+
"@id" : "sch:node6",
10+
"sch:pred6" : [ {
11+
"@id" : "sch:node3"
12+
} ]
13+
} ]
14+
}, {
15+
"@id" : "sch:node4",
16+
"sch:pred4" : [ {
17+
"@id" : "sch:node2"
18+
} ]
19+
}, {
20+
"@id" : "sch:node5",
21+
"sch:pred4" : [ {
22+
"@id" : "sch:node2"
23+
} ],
24+
"sch:pred5" : [ {
25+
"@id" : "sch:node6",
26+
"sch:pred6" : [ {
27+
"@id" : "sch:node3",
28+
"sch:pred4" : [ {
29+
"@id" : "sch:node2"
30+
} ],
31+
"sch:pred5" : [ {
32+
"@id" : "sch:node6"
33+
} ]
34+
} ]
35+
} ]
36+
} ],
37+
"sch:pred3" : [ {
38+
"@id" : "sch:node1",
39+
"sch:pred1" : [ {
40+
"@id" : "sch:node2"
41+
} ]
42+
} ]
43+
} ]

0 commit comments

Comments
 (0)