/* * Copyright 2015 Lukas Krejci * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License */ package org.revapi; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * Represents a single difference between an old and new API element. * * @author Lukas Krejci * @since 0.1 */ public final class Difference { private static abstract class BuilderBase<This extends BuilderBase> { protected String code; protected String name; protected String description; protected Map<CompatibilityType, DifferenceSeverity> classification = new HashMap<>(); protected Map<String, String> attachments = new LinkedHashMap<>(2); @Nonnull public This withCode(@Nonnull String code) { this.code = code; return castThis(); } @Nonnull public This withName(@Nonnull String name) { this.name = name; return castThis(); } @Nonnull public This withDescription(@Nullable String description) { this.description = description; return castThis(); } @Nonnull public This addClassification(@Nonnull CompatibilityType compat, @Nonnull DifferenceSeverity severity) { classification.put(compat, severity); return castThis(); } @Nonnull public This addClassifications(Map<CompatibilityType, DifferenceSeverity> classifications) { classification.putAll(classifications); return castThis(); } @Nonnull public This addAttachment(@Nonnull String key, @Nonnull String value) { attachments.put(key, value); return castThis(); } @Nonnull public This addAttachments(@Nonnull Map<String, String> attachments) { this.attachments.putAll(attachments); return castThis(); } @SuppressWarnings("unchecked") private This castThis() { return (This) this; } } public static final class Builder extends BuilderBase<Builder> { private Builder() { } @Nonnull public Difference build() { return new Difference(code, name, description, classification, attachments); } } public static final class InReportBuilder extends BuilderBase<InReportBuilder> { private final Report.Builder reportBuilder; InReportBuilder(Report.Builder reportBuilder) { this.reportBuilder = reportBuilder; } @Nonnull public Report.Builder done() { Difference p = new Difference(code, name, description, classification, attachments); reportBuilder.differences.add(p); return reportBuilder; } } @Nonnull public static Builder builder() { return new Builder(); } /** * API analyzer dependent unique identification of the reported problem */ public final String code; /** * Human readable name of the problem */ public final String name; /** * Detailed description of the problem */ public final String description; public final Map<CompatibilityType, DifferenceSeverity> classification; /** * The attachments of the difference, keyed by their meaning. Each difference can define a different set of * attachments that correspond to "findings" the difference represents. The map preserves the insertion order. */ public final Map<String, String> attachments; public Difference(@Nonnull String code, @Nonnull String name, @Nullable String description, @Nonnull CompatibilityType compatibility, @Nonnull DifferenceSeverity severity, @Nonnull Map<String, String> attachments) { this(code, name, description, Collections.singletonMap(compatibility, severity), attachments); } public Difference(@Nonnull String code, @Nonnull String name, @Nullable String description, @Nonnull Map<CompatibilityType, DifferenceSeverity> classification, @Nonnull Map<String, String> attachments) { this.code = code; this.name = name; this.description = description; HashMap<CompatibilityType, DifferenceSeverity> tmp = new HashMap<>(classification); this.classification = Collections.unmodifiableMap(tmp); this.attachments = Collections.unmodifiableMap(new LinkedHashMap<>(attachments)); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Difference difference = (Difference) o; return code.equals(difference.code) && classification.equals(difference.classification) && attachments.equals(difference.attachments); } @Override public int hashCode() { int result = code.hashCode(); result = 31 * result + classification.hashCode(); return result; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Problem["); sb.append("code='").append(code).append('\''); sb.append(", name='").append(name).append('\''); sb.append(", classification=").append(classification); sb.append(", description='").append(description).append('\''); sb.append(']'); return sb.toString(); } }