@Override public void process(JCas aJCas) throws AnalysisEngineProcessException { // Keeping track of the ranges of different relation candidates so we wont have duplicate // text snippets for different candidates on the same text Map<IndexRange, IndexRange> rangeMappings = new HashMap<IndexRange, IndexRange>(); if (aggregateJCas == null) aggregateJCas = getEmptyJCas(); CasCopier copier = new CasCopier(aJCas.getCas(), aggregateJCas.getCas()); Iterator<RelationCandidate> iter = JCasUtil.iterator(aJCas, RelationCandidate.class); while (iter.hasNext()) { RelationCandidate candidate = iter.next(); RelationCandidate candidateCopy = (RelationCandidate) copier.copyFs(candidate); // See if we already have this candidate in the aggregate jcas IndexRange candidateRange = new IndexRange(candidate); // The offset between the old jcas and the new of this relation candidate int offset = 0; if (rangeMappings.containsKey(candidateRange)) { offset = rangeMappings.get(candidateRange).getStart() - candidateRange.getStart(); updateAnnotation(candidateCopy, offset); // No need to copy features, has already been done } else { offset = content.length() - candidateRange.getStart(); updateAnnotation(candidateCopy, offset); rangeMappings.put(candidateRange, new IndexRange(candidateCopy)); // For every feature we want to copy for (Class<? extends Annotation> feature : features) { // Iterating over the annotations of this feature type covered by this relation candidate for (Annotation annotation : JCasUtil.selectCovered(aJCas, feature, candidate)) { Annotation cAnnotation = (Annotation) copier.copyFs(annotation); // Updating the indices of the annotation updateAnnotation(cAnnotation, offset); aggregateJCas.addFsToIndexes(cAnnotation); } } // Adding the text content of the relation candidate to the new cas content.append(candidate.getCoveredText()); } aggregateJCas.addFsToIndexes(candidateCopy); } }