com.google.gwt.user.rebind.rpc.TypeHierarchyUtils Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2008 Google Inc.
*
* 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.gwt.user.rebind.rpc;
import com.google.gwt.core.ext.typeinfo.JClassType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
/**
* Collection of utility methods for dealing with type hierarchies.
*/
class TypeHierarchyUtils {
/**
* Returns true
if the type directly implements the specified
* interface. The test is done on erased types; any paramaterizations supplied
* in the arguments are ignored.
*
* @param type type to check
* @param intf interface to look for
* @return true
if the type directly implements the specified
* interface
*/
public static boolean directlyImplementsInterface(JClassType type, JClassType intf) {
type = type.getErasedType();
intf = intf.getErasedType();
return directlyImplementsInterfaceRecursive(new HashSet(), type, intf);
}
/**
* Returns all types on the path from the root type to the serializable
* leaves.
*
* @param root the root type
* @param leaves the set of serializable leaf types
* @return all types on the path from the root type to the serializable leaves
*/
public static List getAllTypesBetweenRootTypeAndLeaves(JClassType root,
Collection leaves) {
Map> adjList = getInvertedTypeHierarchy(root.getErasedType());
Set types = new HashSet();
for (JClassType type : leaves) {
depthFirstSearch(types, adjList, type.getErasedType());
}
return Arrays.asList(types.toArray(new JClassType[0]));
}
/**
* Returns the immediate subtypes of the erased class argument.
*/
public static List getImmediateSubtypes(JClassType clazz) {
List immediateSubtypes = new ArrayList();
clazz = clazz.getErasedType();
for (JClassType subclass : clazz.getSubtypes()) {
JClassType superclass = subclass.getSuperclass();
if (superclass != null) {
superclass = superclass.getErasedType();
}
if (superclass == clazz || clazz.isInterface() != null
&& directlyImplementsInterface(subclass, clazz)) {
immediateSubtypes.add(subclass);
}
}
return immediateSubtypes;
}
private static void addEdge(Map> adjList, JClassType subclass,
JClassType clazz) {
List edges = adjList.get(subclass);
if (edges == null) {
edges = new ArrayList();
adjList.put(subclass, edges);
}
edges.add(clazz);
}
private static void depthFirstSearch(Set seen,
Map> adjList, JClassType type) {
if (seen.contains(type)) {
return;
}
seen.add(type);
List children = adjList.get(type);
if (children != null) {
for (JClassType child : children) {
if (!seen.contains(child)) {
depthFirstSearch(seen, adjList, child);
}
}
}
}
private static boolean directlyImplementsInterfaceRecursive(Set seen,
JClassType clazz, JClassType intf) {
assert (clazz.getErasedType() == clazz);
assert (intf.getErasedType() == intf);
if (clazz == intf) {
return true;
}
JClassType[] intfImpls = clazz.getImplementedInterfaces();
for (JClassType intfImpl : intfImpls) {
intfImpl = intfImpl.getErasedType();
if (!seen.contains(intfImpl)) {
seen.add(intfImpl);
if (directlyImplementsInterfaceRecursive(seen, intfImpl, intf)) {
return true;
}
}
}
return false;
}
/**
* Given a root type return an adjacency list that is the inverted type
* hierarchy.
*/
private static Map> getInvertedTypeHierarchy(JClassType root) {
Map> adjList = new HashMap>();
Set seen = new HashSet();
Stack queue = new Stack();
queue.push(root);
while (!queue.isEmpty()) {
JClassType clazz = queue.pop();
if (seen.contains(clazz)) {
continue;
}
seen.add(clazz);
List immediateSubtypes = getImmediateSubtypes(clazz);
for (JClassType immediateSubtype : immediateSubtypes) {
// Add an edge from the immediate subtype to the supertype
addEdge(adjList, immediateSubtype, clazz);
queue.push(immediateSubtype);
}
}
return adjList;
}
}