com.google.cloud.tools.opensource.classpath.SymbolProblem Maven / Gradle / Ivy
Show all versions of dependencies Show documentation
/*
* Copyright 2019 Google LLC.
*
* 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 com.google.cloud.tools.opensource.classpath;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableSetMultimap;
import java.util.Objects;
import javax.annotation.Nullable;
/**
* A missing or incompatible symbol. This constitutes the cause of a linkage error (without the
* source class).
*
* @see
* Java Dependency Glossary: Linkage Error
*/
public final class SymbolProblem {
private final ErrorType errorType;
private final Symbol symbol;
private final ClassFile containingClass;
public SymbolProblem(Symbol symbol, ErrorType errorType, @Nullable ClassFile containingClass) {
checkNotNull(symbol);
// After finding symbol problem, there is no need to have SuperClassSymbol over ClassSymbol.
this.symbol =
symbol instanceof SuperClassSymbol ? new ClassSymbol(symbol.getClassName()) : symbol;
this.errorType = checkNotNull(errorType);
this.containingClass = containingClass;
}
/** Returns the errorType why the symbol was not resolved. */
ErrorType getErrorType() {
return errorType;
}
/** Returns the target symbol that was not resolved. */
Symbol getSymbol() {
return symbol;
}
/**
* Returns the referenced class that contains the symbol. Null when the target class is not found
* in the class path (this is the case if the errorType is {@code CLASS_NOT_FOUND} for top-level
* classes).
*
* In case of a nested class is missing while its outer class is found in the class path, this
* method returns the outer class.
*/
@Nullable
ClassFile getContainingClass() {
return containingClass;
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
SymbolProblem that = (SymbolProblem) other;
return errorType == that.errorType
&& symbol.equals(that.symbol)
&& Objects.equals(containingClass, that.containingClass);
}
@Override
public int hashCode() {
return Objects.hash(errorType, symbol, containingClass);
}
@Override
public final String toString() {
String jarInfo =
containingClass != null
? String.format("(%s) ", containingClass.getJar().getFileName())
: "";
return jarInfo + getErrorType().getMessage(symbol.toString());
}
public static String formatSymbolProblems(
ImmutableSetMultimap symbolProblems) {
StringBuilder output = new StringBuilder();
symbolProblems
.asMap()
.forEach(
(problem, classFiles) -> {
int referenceCount = classFiles.size();
output.append(
String.format(
"%s;\n referenced by %d class file%s\n",
problem, referenceCount, referenceCount > 1 ? "s" : ""));
classFiles.forEach(
classFile -> {
output.append(" " + classFile.getClassName());
output.append(" (" + classFile.getJar().getFileName() + ")\n");
});
});
return output.toString();
}
}