@Override
  public void process(JCas aJCas) throws AnalysisEngineProcessException {
    CAS cas = aJCas.getCas();

    for (AnnotationFS cover : CasUtil.select(cas, CasUtil.getAnnotationType(cas, annotationType))) {

      // If there is a constraint, check if it matches
      if (constraint != null) {
        JXPathContext ctx = JXPathContext.newContext(cover);
        boolean match = ctx.iterate(constraint).hasNext();
        if (!match) {
          continue;
        }
      }

      // If the target type is a token, use it directly, otherwise select the covered tokens
      Collection<Token> tokens;
      if (cover instanceof Token) {
        tokens = Collections.singleton((Token) cover);
      } else {
        tokens = JCasUtil.selectCovered(aJCas, Token.class, cover);
      }

      for (Token token : tokens) {
        try {
          String semanticField = semanticFieldResource.getSemanticTag(token);
          SemanticField semanticFieldAnnotation =
              new SemanticField(aJCas, token.getBegin(), token.getEnd());
          semanticFieldAnnotation.setValue(semanticField);
          semanticFieldAnnotation.addToIndexes();
        } catch (ResourceAccessException e) {
          throw new AnalysisEngineProcessException(e);
        }
      }
    }
  }