package org.revapi.java.transforms.annotations;
import java.io.Reader;
import java.io.StringReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.jboss.dmr.ModelNode;
import org.revapi.AnalysisContext;
import org.revapi.CompatibilityType;
import org.revapi.Difference;
import org.revapi.DifferenceSeverity;
import org.revapi.DifferenceTransform;
import org.revapi.java.spi.JavaModelElement;
/**
* @author Lukas Krejci
* @since 0.12.0
*/
public final class DownplayHarmlessAnnotationChanges implements DifferenceTransform<JavaModelElement> {
private boolean skip = false;
private static final Set<String> HARMLESS_ANNOTATIONS = new HashSet<>(Arrays.asList(
"java.lang.FunctionalInterface", //having this is purely informational
"java.lang.annotation.Documented" //this doesn't affect the runtime at any rate
));
@Nonnull @Override public Pattern[] getDifferenceCodePatterns() {
return new Pattern[] {exact("java.annotation.added"), exact("java.annotation.removed"),
exact("java.annotation.attributeValueChanged"), exact("java.annotation.attributeAdded"),
exact("java.annotation.attributeRemoved")};
}
@Nullable @Override
public Difference transform(@Nullable JavaModelElement oldElement, @Nullable JavaModelElement newElement,
@Nonnull Difference difference) {
if (skip) {
return difference;
}
String annotationType = difference.attachments.get("annotationType");
if (annotationType == null) {
return difference;
}
if (HARMLESS_ANNOTATIONS.contains(annotationType)) {
return new Difference(difference.code, difference.name, difference.description,
reclassify(difference.classification), difference.attachments);
} else {
return difference;
}
}
@Override public void close() throws Exception {
}
@Nullable @Override public String[] getConfigurationRootPaths() {
return new String[] {"revapi.java.downplayHarmlessAnnotationChanges"};
}
@Nullable @Override public Reader getJSONSchema(@Nonnull String configurationRootPath) {
return new StringReader("{\"type\": \"boolean\"}");
}
@Override public void initialize(@Nonnull AnalysisContext analysisContext) {
ModelNode conf = analysisContext.getConfiguration()
.get("revapi", "java", "downplayHarmlessAnnotationChanges");
if (conf.isDefined()) {
skip = !conf.asBoolean();
}
}
private static Pattern exact(String string) {
return Pattern.compile("^" + Pattern.quote(string) + "$");
}
private static Map<CompatibilityType, DifferenceSeverity> reclassify(Map<CompatibilityType, DifferenceSeverity> orig) {
return orig.keySet().stream()
.collect(Collectors.toMap(Function.identity(), v -> DifferenceSeverity.EQUIVALENT));
}
}