class RemoteRuleMatch {

  private final String ruleId;
  private final String ruleDescription;
  private final String msg;
  private final String context;
  private final int contextOffset;
  private final int offset;
  private final int errorLength;

  private String subId;
  private String shortMsg;
  private List<String> replacements;
  private String url;
  private String category;
  private String categoryId;
  private String locQualityIssueType;

  RemoteRuleMatch(String ruleId, String ruleDescription, String msg, String context, int contextOffset, int offset, int errorLength) {
    this.ruleId = Objects.requireNonNull(ruleId);
    this.ruleDescription = ruleDescription;
    this.msg = Objects.requireNonNull(msg);
    this.context = Objects.requireNonNull(context);
    this.contextOffset = contextOffset;
    this.offset = offset;
    this.errorLength = errorLength;
  }

  /** Unique (per language) identifier for the error. */
  public String getRuleId() {
    return ruleId;
  }

  /** Description of the rule. */
  public String getRuleDescription() {
    return ruleDescription;
  }

  /** Optional sub id (rule groups have a sub id for each rule). */
  public Optional<String> getRuleSubId() {
    return Optional.ofNullable(subId);
  }

  /** A text describing the error to the user. */
  public String getMessage() {
    return msg;
  }

  /** Optional short message describing the error. */
  public Optional<String> getShortMessage() {
    return Optional.ofNullable(shortMsg);
  }

  /**
   * Potential corrections for the error. Note that corrections might be wrong and
   * they are not necessarily ordered by quality.
   */
  public Optional<List<String>> getReplacements() {
    return Optional.ofNullable(replacements);
  }

  /** The error in its context. See {@link #getContextOffset()} and {@link #getErrorLength()} to get the exact position. */
  public String getContext() {
    return context;
  }
  
  /** The character position of the error start inside the result of {@link #getContext()}. */
  public int getContextOffset() {
    return contextOffset;
  }
  
  /** The character position where the error starts. */
  public int getErrorOffset() {
    return offset;
  }
  
  /** The length of the error in characters. */
  public int getErrorLength() {
    return errorLength;
  }

  /** URL with a more detailed explanation of the error. */
  public Optional<String> getUrl() {
    return Optional.ofNullable(url);
  }

  /** The error's category. */
  public Optional<String> getCategory() {
    return Optional.of(category);
  }

  /** The id of the error's category. */
  public Optional<String> getCategoryId() {
    return Optional.of(categoryId);
  }

  public Optional<String> getLocQualityIssueType() {
    return Optional.ofNullable(locQualityIssueType);
  }

  //
  // non-public setters
  //
  
  void setRuleSubId(String subId) {
    this.subId = subId;
  }

  void setShortMsg(String shortMsg) {
    this.shortMsg = shortMsg;
  }

  void setReplacements(List<String> replacements) {
    this.replacements = Collections.unmodifiableList(replacements);
  }

  void setUrl(String url) {
    this.url = url;
  }

  void setCategory(String category) {
    this.category = category;
  }

  void setCategoryId(String categoryId) {
    this.categoryId = categoryId;
  }

  void setLocQualityIssueType(String locQualityIssueType) {
    this.locQualityIssueType = locQualityIssueType;
  }

  @Override
  public String toString() {<FILL_FUNCTION_BODY>}
}

    return ruleId + "@" + offset + "-" + (offset + errorLength);
  
<no_super_class>