com.softicar.platform.common.core.java.classpath.linking.JavaClasspathLinkingValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of platform-common Show documentation
Show all versions of platform-common Show documentation
The SoftiCAR Platform is a lightweight, Java-based library to create interactive business web applications.
package com.softicar.platform.common.core.java.classpath.linking;
import com.softicar.platform.common.core.java.classes.analyzer.AnalyzedJavaClass;
import com.softicar.platform.common.core.java.classes.analyzer.JavaClassAnalyzer;
import com.softicar.platform.common.core.java.classes.name.JavaClassName;
import com.softicar.platform.common.core.java.identifier.declaration.JavaIdentifierDeclaration;
import com.softicar.platform.common.core.java.identifier.key.JavaIdentifierKey;
import com.softicar.platform.common.core.java.method.reference.JavaMethodReference;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Validates referential integrity of the classes on the class path.
*
* Known limitations:
*
* - Only validates method references.
* - No validation of class references is done.
*
*
* @author Oliver Richers
*/
public class JavaClasspathLinkingValidator {
private final Map classesOnClassPath;
private Predicate classFilter;
private JavaClasspathLinkingValidatorResult validatorResult;
public JavaClasspathLinkingValidator(Map classesOnClassPath) {
this.classesOnClassPath = classesOnClassPath;
this.classFilter = dummy -> true;
this.validatorResult = null;
}
/**
* Defines a filter for classes to validate.
*
* @param classFilter
* the class filter (never null)
* @return this object
*/
public JavaClasspathLinkingValidator setClassFilter(Predicate classFilter) {
this.classFilter = classFilter;
return this;
}
public JavaClasspathLinkingValidatorResult validate() {
this.validatorResult = new JavaClasspathLinkingValidatorResult();
validateClasses();
return validatorResult;
}
private void validateClasses() {
classesOnClassPath//
.values()
.stream()
.filter(classFilter)
.collect(Collectors.toList())
.forEach(this::validateClass);
}
private void validateClass(AnalyzedJavaClass javaClass) {
ClassLinkingValidator linkingValidator = new ClassLinkingValidator(javaClass);
javaClass//
.getReferencedMethods(this::isRelevantMethodReference)
.forEach(methodReference -> linkingValidator.validate(methodReference));
}
private boolean isRelevantMethodReference(JavaMethodReference methodReference) {
return !methodReference.getOwner().isArray();
}
private class ClassLinkingValidator {
private final AnalyzedJavaClass referencingClass;
public ClassLinkingValidator(AnalyzedJavaClass referencingClass) {
this.referencingClass = referencingClass;
}
public void validate(JavaMethodReference methodReference) {
Optional methodDeclaration = findMethodDeclaration(methodReference.getOwner(), methodReference.getMethodKey());
if (!methodDeclaration.isPresent()) {
validatorResult.addUnresolvedMethodReference(methodReference, referencingClass);
}
}
private Optional findMethodDeclaration(JavaClassName targetClassName, JavaIdentifierKey methodKey) {
return getAnalyzedJavaClass(targetClassName)//
.flatMap(targetClass -> findMethodDeclaration(targetClass, methodKey));
}
private Optional findMethodDeclaration(AnalyzedJavaClass targetClass, JavaIdentifierKey methodKey) {
Optional methodFromClass = targetClass.findDeclaredMethod(methodKey);
if (methodFromClass.isPresent()) {
return methodFromClass;
}
Optional methodFromInterface = findMethodDeclarationInInterfaces(targetClass, methodKey);
if (methodFromInterface.isPresent()) {
return methodFromInterface;
}
Optional methodFromSuperClass = findMethodDeclarationInSuperClass(targetClass, methodKey);
if (methodFromSuperClass.isPresent()) {
return methodFromSuperClass;
}
return Optional.empty();
}
private Optional findMethodDeclarationInInterfaces(AnalyzedJavaClass targetClass, JavaIdentifierKey methodKey) {
for (JavaClassName interfaceClassName: targetClass.getInterfaces()) {
Optional methodDeclaration = findMethodDeclaration(interfaceClassName, methodKey);
if (methodDeclaration.isPresent()) {
return methodDeclaration;
}
}
return Optional.empty();
}
private Optional findMethodDeclarationInSuperClass(AnalyzedJavaClass targetClass, JavaIdentifierKey methodKey) {
return Optional//
.ofNullable(targetClass.getSuperClass())
.flatMap(superClass -> findMethodDeclaration(superClass, methodKey));
}
private Optional getAnalyzedJavaClass(JavaClassName className) {
AnalyzedJavaClass javaClass = classesOnClassPath.get(className);
if (javaClass != null) {
return Optional.of(javaClass);
} else {
try {
Class clazz = Class.forName(className.getName());
AnalyzedJavaClass analyzedJavaClass = new JavaClassAnalyzer(clazz).analyze();
classesOnClassPath.put(className, analyzedJavaClass);
return Optional.of(analyzedJavaClass);
} catch (@SuppressWarnings("unused") ClassNotFoundException exception) {
validatorResult.addMissingClass(className, referencingClass);
return Optional.empty();
}
}
}
}
}