com.google.security.fences.inheritance.InheritanceGraph Maven / Gradle / Ivy
package com.google.security.fences.inheritance;
import java.util.Map;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
/**
* A lazy-ish graph of sub/super-type relationships between Java classes.
*/
public final class InheritanceGraph {
private final Map classNodes;
private final Function fallback;
InheritanceGraph(
Map classNodes,
Function fallback) {
this.classNodes = Maps.newLinkedHashMap(classNodes);
this.fallback = fallback;
}
/**
* Returns the named node.
*
* @param name an internal class name like {@code com/example/MyClass}.
*/
public Optional named(String name) {
ClassNode node = classNodes.get(name);
if (node == null && !classNodes.containsKey(name)) {
classNodes.put(name, node = fallback.apply(name));
}
return Optional.fromNullable(node);
}
/** A builder that uses the pre-baked system class graph. */
public static Builder builder() {
return new Builder(SystemInheritanceGraph.LAZY_LOADER);
}
static Builder builder(Function fallback) {
return new Builder(fallback);
}
/** A builder for {InheritanceGraph}s. */
public static final class Builder {
private final Map classNodes = Maps.newLinkedHashMap();
private final Function lazyLoadSystemClass;
Builder(final Function lazyLoadSystemClass) {
this.lazyLoadSystemClass = lazyLoadSystemClass;
}
/**
* Defines a relationship between name and its super-interfaces.
*/
public Builder declare(
String name, int access, Optional superClassName,
Iterable extends String> interfaceNames,
Iterable extends MethodDetails> methods,
Iterable extends FieldDetails> fields) {
ClassNode node = classNodes.get(name);
if (node != null) {
// Assume that subsequent declarations are from masked class-files on
// the same class-path.
} else {
node = new ClassNode(
name, access, superClassName, interfaceNames, methods, fields);
classNodes.put(name, node);
}
return this;
}
/** Single use builder. State is cleared after call to build(). */
public InheritanceGraph build() {
return new InheritanceGraph(classNodes, lazyLoadSystemClass);
}
}
/** All the names of class declared, or lazily fetched. */
public Iterable allDeclaredNames() {
return ImmutableList.copyOf(classNodes.keySet());
}
/** All the names of class declared, or lazily fetched. */
public Iterable allDeclaredNodes() {
return ImmutableList.copyOf(classNodes.values());
}
}