You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@reef.apache.org by we...@apache.org on 2015/01/23 00:46:45 UTC

[12/51] [partial] incubator-reef git commit: [REEF-93] Move java sources to lang/java

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java
new file mode 100644
index 0000000..fb34bbb
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/AbstractNode.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.util.MonotonicTreeMap;
+
+import java.util.Collection;
+import java.util.Map;
+
+public abstract class AbstractNode implements Node {
+  protected final Map<String, Node> children = new MonotonicTreeMap<>();
+  private final Node parent;
+  private final String name;
+  private final String fullName;
+
+  public AbstractNode(Node parent, String name, String fullName) {
+    this.parent = parent;
+    this.name = name;
+    this.fullName = fullName;
+    if (parent != null) {
+      if (name.length() == 0) {
+        throw new IllegalArgumentException(
+            "Zero length child name means bad news");
+      }
+      parent.put(this);
+    }
+  }
+
+  @Override
+  public Collection<Node> getChildren() {
+    return children.values();
+  }
+
+  @Override
+  public String getFullName() {
+    return fullName;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == null) return false;
+    if (o == this) return true;
+
+    AbstractNode n = (AbstractNode) o;
+    final boolean parentsEqual;
+    if (n.parent == this.parent) {
+      parentsEqual = true;
+    } else if (n.parent == null) {
+      parentsEqual = false;
+    } else if (this.parent == null) {
+      parentsEqual = false;
+    } else {
+      parentsEqual = n.parent.equals(this.parent);
+    }
+    if (!parentsEqual) {
+      return false;
+    }
+    return this.name.equals(n.name);
+  }
+
+  @Override
+  public Node getParent() {
+    return parent;
+  }
+
+  @Override
+  public boolean contains(String key) {
+    return children.containsKey(key);
+  }
+
+  @Override
+  public Node get(String key) {
+    return children.get(key);
+  }
+
+  @Override
+  public void put(Node n) {
+    children.put(n.getName(), n);
+  }
+
+  @SuppressWarnings("unused")
+  private String toIndentedString(int level) {
+    StringBuilder sb = new StringBuilder();
+    for (int i = 0; i < level; i++) {
+      sb.append("\t");
+    }
+    sb.append(toString() + "\n");
+    if (children != null) {
+      for (Node n : children.values()) {
+        sb.append(((AbstractNode) n).toIndentedString(level + 1));
+      }
+    }
+    return sb.toString();
+  }
+
+  @Override
+  public String toString() {
+    return "[" + this.getClass().getSimpleName() + " '" + getFullName() + "']";
+  }
+
+  @Override
+  public String getName() {
+    return name;
+  }
+
+  @Override
+  public int compareTo(Node n) {
+    return getFullName().compareTo(n.getFullName());
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java
new file mode 100644
index 0000000..672f37a
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ClassNodeImpl.java
@@ -0,0 +1,141 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.types.ClassNode;
+import org.apache.reef.tang.types.ConstructorDef;
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.util.MonotonicSet;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class ClassNodeImpl<T> extends AbstractNode implements ClassNode<T> {
+  private final boolean injectable;
+  private final boolean unit;
+  private final boolean externalConstructor;
+  private final ConstructorDef<T>[] injectableConstructors;
+  private final ConstructorDef<T>[] allConstructors;
+  private final MonotonicSet<ClassNode<T>> knownImpls;
+  private final String defaultImpl;
+
+  public ClassNodeImpl(Node parent, String simpleName, String fullName,
+                       boolean unit, boolean injectable, boolean externalConstructor,
+                       ConstructorDef<T>[] injectableConstructors,
+                       ConstructorDef<T>[] allConstructors,
+                       String defaultImplementation) {
+    super(parent, simpleName, fullName);
+    this.unit = unit;
+    this.injectable = injectable;
+    this.externalConstructor = externalConstructor;
+    this.injectableConstructors = injectableConstructors;
+    this.allConstructors = allConstructors;
+    this.knownImpls = new MonotonicSet<>();
+    this.defaultImpl = defaultImplementation;
+  }
+
+  @Override
+  public ConstructorDef<T>[] getInjectableConstructors() {
+    return injectableConstructors;
+  }
+
+  @Override
+  public ConstructorDef<T>[] getAllConstructors() {
+    return allConstructors;
+  }
+
+  @Override
+  public boolean isInjectionCandidate() {
+    return injectable;
+  }
+
+  @Override
+  public boolean isExternalConstructor() {
+    return externalConstructor;
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder(super.toString() + ": ");
+    if (getInjectableConstructors() != null) {
+      for (ConstructorDef<T> c : getInjectableConstructors()) {
+        sb.append(c.toString() + ", ");
+      }
+    } else {
+      sb.append("OBJECT BUILD IN PROGRESS!  BAD NEWS!");
+    }
+    return sb.toString();
+  }
+
+  public ConstructorDef<T> getConstructorDef(ClassNode<?>... paramTypes)
+      throws BindException {
+    if (!isInjectionCandidate()) {
+      throw new BindException("Cannot @Inject non-static member/local class: "
+          + getFullName());
+    }
+    for (ConstructorDef<T> c : getAllConstructors()) {
+      if (c.takesParameters(paramTypes)) {
+        return c;
+      }
+    }
+    throw new BindException("Could not find requested constructor for class "
+        + getFullName());
+  }
+
+  @Override
+  public void putImpl(ClassNode<T> impl) {
+    knownImpls.add(impl);
+  }
+
+  @Override
+  public Set<ClassNode<T>> getKnownImplementations() {
+    return new MonotonicSet<>(knownImpls);
+  }
+
+  @Override
+  public boolean isUnit() {
+    return unit;
+  }
+
+  @Override
+  public boolean isImplementationOf(ClassNode<?> inter) {
+    List<ClassNode<?>> worklist = new ArrayList<>();
+    if (this.equals(inter)) {
+      return true;
+    }
+    worklist.add(inter);
+    while (!worklist.isEmpty()) {
+      ClassNode<?> cn = worklist.remove(worklist.size() - 1);
+      @SuppressWarnings({"rawtypes", "unchecked"})
+      Set<ClassNode<?>> impls = (Set) cn.getKnownImplementations();
+      if (impls.contains(this)) {
+        return true;
+      }
+      worklist.addAll(impls);
+    }
+    return false;
+  }
+
+  @Override
+  public String getDefaultImplementation() {
+    return defaultImpl;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java
new file mode 100644
index 0000000..8232339
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorArgImpl.java
@@ -0,0 +1,77 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.ConstructorArg;
+
+public class ConstructorArgImpl implements ConstructorArg {
+  private final String type;
+  private final String name;
+  private final boolean isInjectionFuture;
+
+  public ConstructorArgImpl(String type, String namedParameterName, boolean isInjectionFuture) {
+    this.type = type;
+    this.name = namedParameterName;
+    this.isInjectionFuture = isInjectionFuture;
+  }
+
+  @Override
+  public String getName() {
+    return name == null ? type : name;
+  }
+
+  @Override
+  public String getNamedParameterName() {
+    return name;
+  }
+
+  @Override
+  public String getType() {
+    return type;
+  }
+
+  @Override
+  public String toString() {
+    return name == null ? type : type + " " + name;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    ConstructorArgImpl arg = (ConstructorArgImpl) o;
+    if (!type.equals(arg.type)) {
+      return false;
+    }
+    if (name == null && arg.name == null) {
+      return true;
+    }
+    if (name == null && arg.name != null) {
+      return false;
+    }
+    if (name != null && arg.name == null) {
+      return false;
+    }
+    return name.equals(arg.name);
+
+  }
+
+  @Override
+  public boolean isInjectionFuture() {
+    return isInjectionFuture;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java
new file mode 100644
index 0000000..2c27eb1
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/ConstructorDefImpl.java
@@ -0,0 +1,150 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.types.ClassNode;
+import org.apache.reef.tang.types.ConstructorArg;
+import org.apache.reef.tang.types.ConstructorDef;
+
+public class ConstructorDefImpl<T> implements ConstructorDef<T> {
+  private final ConstructorArg[] args;
+  private final String className;
+
+  public ConstructorDefImpl(String className, ConstructorArg[] args,
+                            boolean injectable) throws ClassHierarchyException {
+    this.className = className;
+    this.args = args;
+    if (injectable) {
+      for (int i = 0; i < this.getArgs().length; i++) {
+        for (int j = i + 1; j < this.getArgs().length; j++) {
+          if (this.getArgs()[i].equals(this.getArgs()[j])) {
+            throw new ClassHierarchyException(
+                "Repeated constructor parameter detected.  "
+                    + "Cannot inject constructor " + toString());
+          }
+        }
+      }
+    }
+  }
+
+  @Override
+  public ConstructorArg[] getArgs() {
+    return args;
+  }
+
+  @Override
+  public String getClassName() {
+    return className;
+  }
+
+  private String join(String sep, Object[] vals) {
+    if (vals.length != 0) {
+      StringBuilder sb = new StringBuilder(vals[0].toString());
+      for (int i = 1; i < vals.length; i++) {
+        sb.append(sep + vals[i]);
+      }
+      return sb.toString();
+    } else {
+      return "";
+    }
+  }
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder(className);
+    sb.append("(");
+    sb.append(join(",", args));
+    sb.append(")");
+    return sb.toString();
+  }
+
+  @Override
+  public boolean takesParameters(ClassNode<?>[] paramTypes) {
+    if (paramTypes.length != args.length) {
+      return false;
+    }
+    for (int i = 0; i < paramTypes.length; i++) {
+      if (!args[i].getType().equals(paramTypes[i].getFullName())) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Check to see if two boundConstructors take indistinguishable arguments. If
+   * so (and they are in the same class), then this would lead to ambiguous
+   * injection targets, and we want to fail fast.
+   * <p/>
+   * TODO could be faster. Currently O(n^2) in number of parameters.
+   *
+   * @param def
+   * @return
+   */
+  private boolean equalsIgnoreOrder(ConstructorDef<?> def) {
+    if (getArgs().length != def.getArgs().length) {
+      return false;
+    }
+    for (int i = 0; i < getArgs().length; i++) {
+      boolean found = false;
+      for (int j = 0; j < def.getArgs().length; j++) {
+        if (getArgs()[i].getName().equals(def.getArgs()[j].getName())) {
+          found = true;
+        }
+      }
+      if (!found) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    return equalsIgnoreOrder((ConstructorDef<?>) o);
+  }
+
+  @Override
+  public boolean isMoreSpecificThan(ConstructorDef<?> def) {
+    // Return true if our list of args is a superset of those in def.
+
+    // Is everything in def also in this?
+    for (int i = 0; i < def.getArgs().length; i++) {
+      boolean found = false;
+      for (int j = 0; j < this.getArgs().length; j++) {
+        if (getArgs()[j].equals(def.getArgs()[i])) {
+          found = true;
+          break;
+        }
+      }
+      // If not, then argument j from def is not in our list.  Return false.
+      if (found == false)
+        return false;
+    }
+    // Everything in def's arg list is in ours.  Do we have at least one extra
+    // argument?
+    return getArgs().length > def.getArgs().length;
+  }
+
+  @Override
+  public int compareTo(ConstructorDef<?> o) {
+    return toString().compareTo(o.toString());
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java
new file mode 100644
index 0000000..f2e796d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/NamedParameterNodeImpl.java
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.NamedParameterNode;
+import org.apache.reef.tang.types.Node;
+
+public class NamedParameterNodeImpl<T> extends AbstractNode implements
+    NamedParameterNode<T> {
+  private final String fullArgName;
+  private final String simpleArgName;
+  private final String documentation;
+  private final String shortName;
+  private final String[] defaultInstanceAsStrings;
+  private final boolean isSet;
+  private final boolean isList;
+
+  public NamedParameterNodeImpl(Node parent, String simpleName,
+                                String fullName, String fullArgName, String simpleArgName, boolean isSet, boolean isList,
+                                String documentation, String shortName, String[] defaultInstanceAsStrings) {
+    super(parent, simpleName, fullName);
+    this.fullArgName = fullArgName;
+    this.simpleArgName = simpleArgName;
+    this.isSet = isSet;
+    this.isList = isList;
+    this.documentation = documentation;
+    this.shortName = shortName;
+    this.defaultInstanceAsStrings = defaultInstanceAsStrings;
+  }
+
+  @Override
+  public String toString() {
+    return getSimpleArgName() + " " + getName();
+  }
+
+  @Override
+  public String getSimpleArgName() {
+    return simpleArgName;
+  }
+
+  @Override
+  public String getFullArgName() {
+    return fullArgName;
+  }
+
+  @Override
+  public String getDocumentation() {
+    return documentation;
+  }
+
+  @Override
+  public String getShortName() {
+    return shortName;
+  }
+
+  @Override
+  public String[] getDefaultInstanceAsStrings() {
+    return defaultInstanceAsStrings;
+  }
+
+  @Override
+  public boolean isSet() {
+    return isSet;
+  }
+
+  @Override
+  public boolean isList() {
+    return isList;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java
new file mode 100644
index 0000000..16ee0aa
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/PackageNodeImpl.java
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.implementation.types;
+
+import org.apache.reef.tang.types.Node;
+import org.apache.reef.tang.types.PackageNode;
+
+public class PackageNodeImpl extends AbstractNode implements PackageNode {
+  public PackageNodeImpl(Node parent, String name, String fullName) {
+    super(parent, name, fullName);
+  }
+
+  public PackageNodeImpl() {
+    this(null, "", "[root node]");
+  }
+
+  /**
+   * Unlike normal nodes, the root node needs to take the package name of its
+   * children into account.  Therefore, we use the full name as the key when
+   * we insert nodes into the root.
+   */
+  @Override
+  public void put(Node n) {
+    super.children.put(n.getFullName(), n);
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java
new file mode 100644
index 0000000..9b0f605
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/implementation/types/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+/**
+ * Implementations of the ClassHierarchy type system.  These classes encode
+ * language independent data.  Java specializations of these types are in
+ * org.apache.reef.tang.implementation.java.
+ */
+
+package org.apache.reef.tang.implementation.types;
+

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java
new file mode 100644
index 0000000..23b203f
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/package-info.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+/**
+ * Public interfaces and factories for Tang's core API.
+ *
+ * Other packages that are of interest to typical Tang use-cases are
+ * org.apache.reef.tang.annotations which contains Java annotations that encode
+ * Tang configuration metadata, and org.apache.reef.tang.formats, which
+ * contains classes that import and export data from Tang in various formats.
+ */
+package org.apache.reef.tang;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java
new file mode 100644
index 0000000..8c5c19b
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ClassNode.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.types;
+
+import org.apache.reef.tang.exceptions.BindException;
+
+import java.util.Set;
+
+public interface ClassNode<T> extends Node {
+
+  public ConstructorDef<T>[] getInjectableConstructors();
+
+  public ConstructorDef<T> getConstructorDef(ClassNode<?>... args)
+      throws BindException;
+
+  public ConstructorDef<T>[] getAllConstructors();
+
+  public void putImpl(ClassNode<T> impl);
+
+  public Set<ClassNode<T>> getKnownImplementations();
+
+  public String getDefaultImplementation();
+
+  public boolean isUnit();
+
+  public boolean isInjectionCandidate();
+
+  public boolean isExternalConstructor();
+
+  public boolean isImplementationOf(ClassNode<?> inter);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java
new file mode 100644
index 0000000..811af9e
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorArg.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.types;
+
+public interface ConstructorArg {
+
+  public String getName();
+
+  public String getType();
+
+  public boolean isInjectionFuture();
+
+  public String getNamedParameterName();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java
new file mode 100644
index 0000000..92922c7
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/ConstructorDef.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.types;
+
+public interface ConstructorDef<T> extends Comparable<ConstructorDef<?>> {
+  public String getClassName();
+
+  public ConstructorArg[] getArgs();
+
+  public boolean isMoreSpecificThan(ConstructorDef<?> def);
+
+  public boolean takesParameters(ClassNode<?>[] paramTypes);
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java
new file mode 100644
index 0000000..94d0f9c
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/NamedParameterNode.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.types;
+
+public interface NamedParameterNode<T> extends Node {
+
+  public String getDocumentation();
+
+  public String getShortName();
+
+  public String[] getDefaultInstanceAsStrings();
+
+  public String getSimpleArgName();
+
+  public String getFullArgName();
+
+  public boolean isSet();
+
+  public boolean isList();
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java
new file mode 100644
index 0000000..53d5ac5
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Node.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.types;
+
+import java.util.Collection;
+
+public interface Node extends Comparable<Node>, Traversable<Node> {
+
+  String getName();
+
+  String getFullName();
+
+  boolean contains(String key);
+
+  Node get(String key);
+
+  Node getParent();
+
+  void put(Node node);
+
+  @Override
+  Collection<Node> getChildren();
+
+  @Override
+  String toString();
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java
new file mode 100644
index 0000000..5e7f20d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/PackageNode.java
@@ -0,0 +1,23 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.types;
+
+public interface PackageNode extends Node {
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java
new file mode 100644
index 0000000..445435c
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/Traversable.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.types;
+
+import java.util.Collection;
+
+public interface Traversable<T extends Traversable<T>> {
+
+  Collection<T> getChildren();
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java
new file mode 100644
index 0000000..c76fe0e
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/types/package-info.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+/**
+ * The interfaces that define Tang's ClassHierarchy objects.  ClassHierarchies
+ * can be thought of as read-only caches of the reflection data that is
+ * produced when applications are compiled.
+ */
+
+package org.apache.reef.tang.types;
+

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java
new file mode 100644
index 0000000..31c023d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/AbstractMonotonicMultiMap.java
@@ -0,0 +1,206 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+public abstract class AbstractMonotonicMultiMap<K, V> implements Collection<Entry<K, V>> {
+  protected Map<K, Set<V>> map;
+  private int size = 0;
+
+  public AbstractMonotonicMultiMap(Map<K, Set<V>> map) {
+    this.map = map;
+  }
+
+  public void put(K key, V v) {
+    Set<V> vals = map.get(key);
+    if (vals == null) {
+      vals = new MonotonicHashSet<V>();
+      map.put(key, vals);
+    }
+    vals.add(v);
+    size++;
+  }
+
+  public Set<K> keySet() {
+    return map.keySet();
+  }
+
+  public Set<V> getValuesForKey(K key) {
+    Set<V> ret = map.get(key);
+    if (ret == null) {
+      return new MonotonicHashSet<V>();
+    } else {
+      return ret;
+    }
+  }
+
+  public boolean contains(K key, V v) {
+    Set<V> vals = map.get(key);
+    if (vals != null) {
+      return vals.contains(v);
+    }
+    return false;
+  }
+
+  @Override
+  public boolean add(Entry<K, V> e) {
+    put(e.getKey(), e.getValue());
+    return true;
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends Entry<K, V>> c) {
+    boolean ret = false;
+    for (Entry<K, V> e : c) {
+      add(e);
+      ret = true;
+    }
+    return ret;
+  }
+
+  @Override
+  public void clear() {
+    throw new UnsupportedOperationException("MonotonicMultiMap cannot be cleared!");
+  }
+
+  @SuppressWarnings("unchecked")
+  @Override
+  public boolean contains(Object o) {
+    Entry<?, ?> e = (Entry<?, ?>) o;
+    return contains((K) e.getKey(), (V) e.getValue());
+  }
+
+  @Override
+  public boolean containsAll(Collection<?> c) {
+    for (Object o : c) {
+      if (!contains(o)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return size == 0;
+  }
+
+  @Override
+  public Iterator<Entry<K, V>> iterator() {
+    final Iterator<Entry<K, Set<V>>> it = map.entrySet().iterator();
+    return new Iterator<Entry<K, V>>() {
+      Iterator<V> cur;
+      K curKey;
+
+      @Override
+      public boolean hasNext() {
+        return it.hasNext() || (cur != null && cur.hasNext());
+      }
+
+      @Override
+      public Entry<K, V> next() {
+        if (cur == null) {
+          if (it.hasNext()) {
+            Entry<K, Set<V>> e = it.next();
+            curKey = e.getKey();
+            cur = e.getValue().iterator();
+          }
+        }
+        final K k = curKey;
+        final V v = cur.next();
+        if (!cur.hasNext()) {
+          cur = null;
+        }
+
+        return new Entry<K, V>() {
+
+          @Override
+          public K getKey() {
+            return k;
+          }
+
+          @Override
+          public V getValue() {
+            return v;
+          }
+
+          @Override
+          public V setValue(V value) {
+            throw new UnsupportedOperationException();
+          }
+
+        };
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+
+    };
+  }
+
+  public Set<V> values() {
+    Set<V> s = new HashSet<>();
+    for (Entry<K, V> e : this) {
+      s.add(e.getValue());
+    }
+    return s;
+  }
+
+  @Override
+  public boolean remove(Object o) {
+    throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method remove!");
+  }
+
+  @Override
+  public boolean removeAll(Collection<?> c) {
+    throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method removeAll!");
+  }
+
+  @Override
+  public boolean retainAll(Collection<?> c) {
+    throw new UnsupportedOperationException("MonotonicMultiMap does not support non-monotonic method retainAll!");
+  }
+
+  @Override
+  public int size() {
+    return size;
+  }
+
+  @Override
+  public Entry<K, V>[] toArray() {
+    throw new UnsupportedOperationException("No toArray() for MonotonicMulitMap (yet)");
+  }
+
+  @Override
+  public <T> T[] toArray(T[] a) {
+    throw new UnsupportedOperationException("No toArray() for MonotonicMulitMap (yet)");
+  }
+
+  public boolean containsKey(K k) {
+    if (map.containsKey(k)) {
+      return !getValuesForKey(k).isEmpty();
+    } else {
+      return false;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java
new file mode 100644
index 0000000..8c5cc6d
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashMap.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MonotonicHashMap<T, U> extends HashMap<T, U> {
+  private static final long serialVersionUID = 1L;
+
+  @Override
+  public U put(T key, U value) {
+    U old = super.get(key);
+    if (old != null) {
+      throw new IllegalArgumentException("Attempt to re-add: [" + key
+          + "] old value: " + old + " new value " + value);
+    }
+    return super.put(key, value);
+  }
+
+  @Override
+  public void putAll(Map<? extends T, ? extends U> m) {
+    for (T t : m.keySet()) {
+      if (containsKey(t)) {
+        put(t, m.get(t)); // guaranteed to throw.
+      }
+    }
+    for (T t : m.keySet()) {
+      put(t, m.get(t));
+    }
+  }
+
+  @Override
+  public void clear() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public U remove(Object o) {
+    throw new UnsupportedOperationException();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java
new file mode 100644
index 0000000..aa9b12e
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicHashSet.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+
+public class MonotonicHashSet<T> extends HashSet<T> {
+  private static final long serialVersionUID = 1L;
+
+  public MonotonicHashSet() {
+    super();
+  }
+
+  public MonotonicHashSet(Collection<T> c) {
+    super(c);
+  }
+
+  @SafeVarargs
+  public MonotonicHashSet(T... c) {
+    super(Arrays.asList(c));
+  }
+
+  @Override
+  public boolean add(T e) {
+    if (super.contains(e)) {
+      throw new IllegalArgumentException("Attempt to re-add " + e
+          + " to MonotonicSet!");
+    }
+    return super.add(e);
+  }
+
+  @Override
+  public void clear() {
+    throw new UnsupportedOperationException("Attempt to clear MonotonicSet!");
+  }
+
+  @Override
+  public boolean remove(Object o) {
+    throw new UnsupportedOperationException("Attempt to remove " + o
+        + " from MonotonicSet!");
+  }
+
+  @Override
+  public boolean removeAll(Collection<?> c) {
+    throw new UnsupportedOperationException(
+        "removeAll() doesn't make sense for MonotonicSet!");
+  }
+
+  @Override
+  public boolean retainAll(Collection<?> c) {
+    throw new UnsupportedOperationException(
+        "retainAll() doesn't make sense for MonotonicSet!");
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends T> c) {
+    for (T t : c) {
+      add(t);
+    }
+    return c.size() != 0;
+  }
+
+  public boolean addAllIgnoreDuplicates(Collection<? extends T> c) {
+    boolean ret = false;
+    for (T t : c) {
+      if (!contains(t)) {
+        add(t);
+        ret = true;
+      }
+    }
+    return ret;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java
new file mode 100644
index 0000000..34cdeea
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiHashMap.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+public class MonotonicMultiHashMap<K, V> extends AbstractMonotonicMultiMap<K, V> {
+  public MonotonicMultiHashMap() {
+    super(new MonotonicHashMap<K, java.util.Set<V>>());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java
new file mode 100644
index 0000000..3eb7ecb
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicMultiMap.java
@@ -0,0 +1,25 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+public class MonotonicMultiMap<K, V> extends AbstractMonotonicMultiMap<K, V> {
+  public MonotonicMultiMap() {
+    super(new MonotonicTreeMap<K, java.util.Set<V>>());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java
new file mode 100644
index 0000000..c272e4f
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicSet.java
@@ -0,0 +1,91 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.TreeSet;
+
+public class MonotonicSet<T> extends TreeSet<T> {
+  private static final long serialVersionUID = 1L;
+
+  public MonotonicSet() {
+    super();
+  }
+
+  public MonotonicSet(TreeSet<T> c) {
+    super(c.comparator());
+    addAll(c);
+  }
+
+  public MonotonicSet(Comparator<T> c) {
+    super(c);
+  }
+
+  @Override
+  public boolean add(T e) {
+    if (super.contains(e)) {
+      throw new IllegalArgumentException("Attempt to re-add " + e
+          + " to MonotonicSet!");
+    }
+    return super.add(e);
+  }
+
+  @Override
+  public void clear() {
+    throw new UnsupportedOperationException("Attempt to clear MonotonicSet!");
+  }
+
+  @Override
+  public boolean remove(Object o) {
+    throw new UnsupportedOperationException("Attempt to remove " + o
+        + " from MonotonicSet!");
+  }
+
+  @Override
+  public boolean removeAll(Collection<?> c) {
+    throw new UnsupportedOperationException(
+        "removeAll() doesn't make sense for MonotonicSet!");
+  }
+
+  @Override
+  public boolean retainAll(Collection<?> c) {
+    throw new UnsupportedOperationException(
+        "retainAll() doesn't make sense for MonotonicSet!");
+  }
+
+  @Override
+  public boolean addAll(Collection<? extends T> c) {
+    for (T t : c) {
+      add(t);
+    }
+    return c.size() != 0;
+  }
+
+  public boolean addAllIgnoreDuplicates(Collection<? extends T> c) {
+    boolean ret = false;
+    for (T t : c) {
+      if (!contains(t)) {
+        add(t);
+        ret = true;
+      }
+    }
+    return ret;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java
new file mode 100644
index 0000000..3b84311
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/MonotonicTreeMap.java
@@ -0,0 +1,119 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+public final class MonotonicTreeMap<T, U> implements Map<T, U> {
+  private static final long serialVersionUID = 1L;
+
+  private final TreeMap<T, U> innerMap = new TreeMap<>();
+
+
+  @Override
+  public int size() {
+    return innerMap.size();
+  }
+
+  @Override
+  public boolean isEmpty() {
+    return innerMap.isEmpty();
+  }
+
+  @Override
+  public boolean containsKey(final Object o) {
+    return innerMap.containsKey(o);
+  }
+
+  @Override
+  public boolean containsValue(final Object o) {
+    return innerMap.containsValue(o);
+  }
+
+  @Override
+  public U get(final Object o) {
+    return innerMap.get(o);
+  }
+
+  @Override
+  public U put(T key, U value) {
+    U old = innerMap.get(key);
+    if (old != null) {
+      throw new IllegalArgumentException("Attempt to re-add: [" + key
+          + "]\n old value: " + old + " new value " + value);
+    }
+    return innerMap.put(key, value);
+  }
+
+  @Override
+  public void putAll(Map<? extends T, ? extends U> m) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public void clear() {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public Set<T> keySet() {
+    return innerMap.keySet();
+  }
+
+  @Override
+  public Collection<U> values() {
+    return innerMap.values();
+  }
+
+  @Override
+  public Set<Entry<T, U>> entrySet() {
+    return innerMap.entrySet();
+  }
+
+  @Override
+  public U remove(Object o) {
+    throw new UnsupportedOperationException();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    final MonotonicTreeMap that = (MonotonicTreeMap) o;
+
+    if (!innerMap.equals(that.innerMap)) {
+      return false;
+    }
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return innerMap.hashCode();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java
new file mode 100644
index 0000000..3157ba8
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/main/java/org/apache/reef/tang/util/ReflectionUtilities.java
@@ -0,0 +1,397 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.reef.tang.util;
+
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+
+import javax.inject.Inject;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.*;
+import java.util.*;
+
+public class ReflectionUtilities {
+  /**
+   * This is used to split Java classnames.  Currently, we split on . and on $
+   */
+  public final static String regexp = "[\\.\\$]";
+  /**
+   * A map from numeric classes to the number of bits used by their representations.
+   */
+  private final static Map<Class<?>, Integer> sizeof = new HashMap<>();
+
+  static {
+    sizeof.put(Byte.class, Byte.SIZE);
+    sizeof.put(Short.class, Short.SIZE);
+    sizeof.put(Integer.class, Integer.SIZE);
+    sizeof.put(Long.class, Long.SIZE);
+    sizeof.put(Float.class, Float.SIZE);
+    sizeof.put(Double.class, Double.SIZE);
+  }
+
+  /**
+   * Given a primitive type, return its boxed representation.
+   * <p/>
+   * Examples:
+   * boxClass(int.class) -> Integer.class
+   * boxClass(String.class) -> String.class
+   *
+   * @param c The class to be boxed.
+   * @return The boxed version of c, or c if it is not a primitive type.
+   */
+  public static Class<?> boxClass(Class<?> c) {
+    if (c.isPrimitive() && c != Class.class) {
+      if (c == boolean.class) {
+        return Boolean.class;
+      } else if (c == byte.class) {
+        return Byte.class;
+      } else if (c == char.class) {
+        return Character.class;
+      } else if (c == short.class) {
+        return Short.class;
+      } else if (c == int.class) {
+        return Integer.class;
+      } else if (c == long.class) {
+        return Long.class;
+      } else if (c == float.class) {
+        return Float.class;
+      } else if (c == double.class) {
+        return Double.class;
+      } else if (c == void.class) {
+        return Void.class;
+      } else {
+        throw new UnsupportedOperationException(
+            "Encountered unknown primitive type!");
+      }
+    } else {
+      return c;
+    }
+  }
+
+  /**
+   * Given a Type, return all of the classes it extends and interfaces it implements (including the class itself).
+   * <p/>
+   * Examples:
+   * Integer.class -> {Integer.class, Number.class, Object.class}
+   * T -> Object
+   * ? -> Object
+   * HashSet<T> -> {HashSet<T>, Set<T>, Collection<T>, Object}
+   * FooEventHandler -> {FooEventHandler, EventHandler<Foo>, Object}
+   */
+  public static Iterable<Type> classAndAncestors(Type c) {
+    List<Type> workQueue = new ArrayList<>();
+
+    workQueue.add(c);
+    if (getRawClass(c).isInterface()) {
+      workQueue.add(Object.class);
+    }
+    for (int i = 0; i < workQueue.size(); i++) {
+      c = workQueue.get(i);
+
+      if (c instanceof Class) {
+        Class<?> clz = (Class<?>) c;
+        final Type sc = clz.getSuperclass();
+        if (sc != null) workQueue.add(sc); //c.getSuperclass());
+        workQueue.addAll(Arrays.asList(clz.getGenericInterfaces()));
+      } else if (c instanceof ParameterizedType) {
+        ParameterizedType pt = (ParameterizedType) c;
+        Class<?> rawPt = (Class<?>) pt.getRawType();
+        final Type sc = rawPt.getSuperclass();
+//        workQueue.add(pt);
+//        workQueue.add(rawPt);
+        if (sc != null) workQueue.add(sc);
+        workQueue.addAll(Arrays.asList(rawPt.getGenericInterfaces()));
+      } else if (c instanceof WildcardType) {
+        workQueue.add(Object.class); // XXX not really correct, but close enough?
+      } else if (c instanceof TypeVariable) {
+        workQueue.add(Object.class); // XXX not really correct, but close enough?
+      } else {
+        throw new RuntimeException(c.getClass() + " " + c + " is of unknown type!");
+      }
+    }
+    return workQueue;
+  }
+
+  /**
+   * Check to see if one class can be coerced into another.  A class is
+   * coercable to another if, once both are boxed, the target class is a
+   * superclass or implemented interface of the source class.
+   * <p/>
+   * If both classes are numeric types, then this method returns true iff
+   * the conversion will not result in a loss of precision.
+   * <p/>
+   * TODO: Float and double are currently coercible to int and long.  This is a bug.
+   */
+  public static boolean isCoercable(Class<?> to, Class<?> from) {
+    to = boxClass(to);
+    from = boxClass(from);
+    if (Number.class.isAssignableFrom(to)
+        && Number.class.isAssignableFrom(from)) {
+      return sizeof.get(from) <= sizeof.get(to);
+    }
+    return to.isAssignableFrom(from);
+  }
+
+  /**
+   * Lookup the provided name using the provided classloader. This method
+   * includes special handling for primitive types, which can be looked up
+   * by short name (all other types need to be looked up by long name).
+   *
+   * @throws ClassNotFoundException
+   */
+  public static Class<?> classForName(String name, ClassLoader loader)
+      throws ClassNotFoundException {
+    if (name.startsWith("[")) {
+      throw new UnsupportedOperationException("No support for arrays, etc.  Name was: " + name);
+    } else if (name.equals("boolean")) {
+      return boolean.class;
+    } else if (name.equals("byte")) {
+      return byte.class;
+    } else if (name.equals("char")) {
+      return char.class;
+    } else if (name.equals("short")) {
+      return short.class;
+    } else if (name.equals("int")) {
+      return int.class;
+    } else if (name.equals("long")) {
+      return long.class;
+    } else if (name.equals("float")) {
+      return float.class;
+    } else if (name.equals("double")) {
+      return double.class;
+    } else if (name.equals("void")) {
+      return void.class;
+    } else {
+      return loader.loadClass(name);
+    }
+  }
+
+  /**
+   * Get the simple name of the class. This varies from the one in Class, in
+   * that it returns "1" for Classes like java.lang.String$1 In contrast,
+   * String.class.getSimpleName() returns "", which is not unique if
+   * java.lang.String$2 exists, causing all sorts of strange bugs.
+   *
+   * @param name
+   * @return
+   */
+  public static String getSimpleName(Type name) {
+    final Class<?> clazz = getRawClass(name);
+    final String[] nameArray = clazz.getName().split(regexp);
+    final String ret = nameArray[nameArray.length - 1];
+    if (ret.length() == 0) {
+      throw new IllegalArgumentException("Class " + name + " has zero-length simple name.  Can't happen?!?");
+    }
+    return ret;
+  }
+
+  /**
+   * Return the full name of the raw type of the provided Type.
+   * <p/>
+   * Examples:
+   * <p/>
+   * java.lang.String.class -> "java.lang.String"
+   * Set<String> -> "java.util.Set"  // such types can occur as constructor arguments, for example
+   *
+   * @param name
+   * @return
+   */
+  public static String getFullName(Type name) {
+    return getRawClass(name).getName();
+  }
+
+  /**
+   * Return the full name of the provided field.  This will be globally
+   * unique.  Following Java semantics, the full name will have all the
+   * generic parameters stripped out of it.
+   * <p/>
+   * Example:
+   * <p/>
+   * Set<X> { int size; } -> java.util.Set.size
+   */
+  public static String getFullName(Field f) {
+    return getFullName(f.getDeclaringClass()) + "." + f.getName();
+  }
+
+  /**
+   * This method takes a class called clazz that *directly* implements a generic interface or generic class, iface.
+   * Iface should take a single parameter, which this method will return.
+   * <p/>
+   * TODO This is only tested for interfaces, and the type parameters associated with method arguments.
+   * TODO Not sure what we should do in the face of deeply nested generics (eg: Set<Set<String>)
+   * TODO Recurse up the class hierarchy in case there are intermediate interfaces
+   *
+   * @param iface A generic interface; we're looking up it's first (and only) parameter.
+   * @param type  A type that is more specific than clazz, or clazz if no such type is available.
+   * @return The class implemented by the interface, or null(?) if the instantiation was not generic.
+   * @throws IllegalArgumentException if clazz does not directly implement iface.
+   */
+  static public Type getInterfaceTarget(final Class<?> iface, final Type type) throws IllegalArgumentException {
+    if (type instanceof ParameterizedType) {
+      final ParameterizedType pt = (ParameterizedType) type;
+      if (iface.isAssignableFrom((Class<?>) pt.getRawType())) {
+        Type t = pt.getActualTypeArguments()[0];
+        return t;
+      } else {
+        throw new IllegalArgumentException("Parameterized type " + type + " does not extend " + iface);
+      }
+    } else if (type instanceof Class) {
+      final Class<?> clazz = (Class<?>) type;
+
+      if (!clazz.equals(type)) {
+        throw new IllegalArgumentException();
+      }
+
+      ArrayList<Type> al = new ArrayList<>();
+      al.addAll(Arrays.asList(clazz.getGenericInterfaces()));
+      Type sc = clazz.getGenericSuperclass();
+      if (sc != null) al.add(sc);
+
+      final Type[] interfaces = al.toArray(new Type[0]);
+
+      for (Type genericNameType : interfaces) {
+        if (genericNameType instanceof ParameterizedType) {
+          ParameterizedType ptype = (ParameterizedType) genericNameType;
+          if (ptype.getRawType().equals(iface)) {
+            Type t = ptype.getActualTypeArguments()[0];
+            return t;
+          }
+        }
+      }
+      throw new IllegalArgumentException(clazz + " does not directly implement " + iface);
+    } else {
+      throw new UnsupportedOperationException("Do not know how to get interface target of " + type);
+    }
+  }
+
+  /**
+   * @param clazz
+   * @return T if clazz implements Name<T>, null otherwise
+   * @throws BindException If clazz's definition incorrectly uses Name or @NamedParameter
+   */
+  static public Type getNamedParameterTargetOrNull(Class<?> clazz)
+      throws ClassHierarchyException {
+    Annotation npAnnotation = clazz.getAnnotation(NamedParameter.class);
+    boolean hasSuperClass = (clazz.getSuperclass() != Object.class);
+
+    boolean isInjectable = false;
+    boolean hasConstructor = false;
+    // TODO Figure out how to properly differentiate between default and
+    // non-default zero-arg constructors?
+    Constructor<?>[] constructors = clazz.getDeclaredConstructors();
+    if (constructors.length > 1) {
+      hasConstructor = true;
+    }
+    if (constructors.length == 1) {
+      Constructor<?> c = constructors[0];
+      Class<?>[] p = c.getParameterTypes();
+      if (p.length > 1) {
+        // Multiple args. Definitely not implicit.
+        hasConstructor = true;
+      } else if (p.length == 1) {
+        // One arg. Could be an inner class, in which case the compiler
+        // included an implicit one parameter constructor that takes the
+        // enclosing type.
+        if (p[0] != clazz.getEnclosingClass()) {
+          hasConstructor = true;
+        }
+      }
+    }
+    for (Constructor<?> c : constructors) {
+      for (Annotation a : c.getDeclaredAnnotations()) {
+        if (a instanceof Inject) {
+          isInjectable = true;
+        }
+      }
+    }
+
+    Class<?>[] allInterfaces = clazz.getInterfaces();
+
+    boolean hasMultipleInterfaces = (allInterfaces.length > 1);
+    boolean implementsName;
+    Type parameterClass = null;
+    try {
+      parameterClass = getInterfaceTarget(Name.class, clazz);
+      implementsName = true;
+    } catch (IllegalArgumentException e) {
+      implementsName = false;
+    }
+
+    if (npAnnotation == null) {
+      if (implementsName) {
+        throw new ClassHierarchyException("Named parameter " + getFullName(clazz)
+            + " is missing its @NamedParameter annotation.");
+      } else {
+        return null;
+      }
+    } else {
+      if (!implementsName) {
+        throw new ClassHierarchyException("Found illegal @NamedParameter " + getFullName(clazz)
+            + " does not implement Name<?>");
+      }
+      if (hasSuperClass) {
+        throw new ClassHierarchyException("Named parameter " + getFullName(clazz)
+            + " has a superclass other than Object.");
+      }
+      if (hasConstructor || isInjectable) {
+        throw new ClassHierarchyException("Named parameter " + getFullName(clazz) + " has "
+            + (isInjectable ? "an injectable" : "a") + " constructor. "
+            + " Named parameters must not declare any constructors.");
+      }
+      if (hasMultipleInterfaces) {
+        throw new ClassHierarchyException("Named parameter " + getFullName(clazz) + " implements "
+            + "multiple interfaces.  It is only allowed to implement Name<T>");
+      }
+      if (parameterClass == null) {
+        throw new ClassHierarchyException(
+            "Missing type parameter in named parameter declaration.  " + getFullName(clazz)
+                + " implements raw type Name, but must implement"
+                + " generic type Name<T>.");
+      }
+      return parameterClass;
+    }
+  }
+
+  /**
+   * Coerce a Type into a Class.  This strips out any generic paramters, and
+   * resolves wildcards and free parameters to Object.
+   * <p/>
+   * Examples:
+   * java.util.Set<String> -> java.util.Set
+   * ? extends T -> Object
+   * T -> Object
+   * ? -> Object
+   */
+  public static Class<?> getRawClass(Type clazz) {
+    if (clazz instanceof Class) {
+      return (Class<?>) clazz;
+    } else if (clazz instanceof ParameterizedType) {
+      return (Class<?>) ((ParameterizedType) clazz).getRawType();
+    } else if (clazz instanceof WildcardType) {
+      return Object.class; // XXX not really correct, but close enough?
+    } else if (clazz instanceof TypeVariable) {
+      return Object.class; // XXX not really correct, but close enough?
+    } else {
+      System.err.println("Can't getRawClass for " + clazz + " of unknown type " + clazz.getClass());
+      throw new IllegalArgumentException("Can't getRawClass for " + clazz + " of unknown type " + clazz.getClass());
+    }
+  }
+}