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:41 UTC

[08/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/test/java/org/apache/reef/tang/implementation/TestClassHierarchy.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/TestClassHierarchy.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/TestClassHierarchy.java
new file mode 100644
index 0000000..4c4c2cd
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/TestClassHierarchy.java
@@ -0,0 +1,642 @@
+/**
+ * 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;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.annotations.*;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.exceptions.InjectionException;
+import org.apache.reef.tang.exceptions.NameResolutionException;
+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.ReflectionUtilities;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javax.inject.Inject;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@DefaultImplementation(String.class)
+interface BadIfaceDefault {
+}
+
+interface I1 {
+}
+
+public class TestClassHierarchy {
+  public ClassHierarchy ns;
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Before
+  public void setUp() throws Exception {
+    TangImpl.reset();
+    ns = Tang.Factory.getTang().getDefaultClassHierarchy();
+  }
+
+  public String s(Class<?> c) {
+    return ReflectionUtilities.getFullName(c);
+  }
+
+  @Test
+  public void testJavaString() throws NameResolutionException {
+    ns.getNode(ReflectionUtilities.getFullName(String.class));
+    Node n = null;
+    try {
+      n = ns.getNode("java");
+    } catch (NameResolutionException e) {
+    }
+    Assert.assertNull(n);
+    try {
+      n = ns.getNode("java.lang");
+    } catch (NameResolutionException e) {
+    }
+    Assert.assertNull(n);
+    Assert.assertNotNull(ns.getNode("java.lang.String"));
+    try {
+      ns.getNode("com.microsoft");
+      Assert.fail("Didn't get expected exception");
+    } catch (NameResolutionException e) {
+
+    }
+  }
+
+  @Test
+  public void testSimpleConstructors() throws NameResolutionException {
+    ClassNode<?> cls = (ClassNode<?>) ns.getNode(s(SimpleConstructors.class));
+    Assert.assertTrue(cls.getChildren().size() == 0);
+    ConstructorDef<?> def[] = cls.getInjectableConstructors();
+    Assert.assertEquals(3, def.length);
+  }
+
+  @Test
+  public void testNamedParameterConstructors() throws NameResolutionException {
+    ns.getNode(s(NamedParameterConstructors.class));
+  }
+
+  @Test
+  public void testArray() throws NameResolutionException {
+    thrown.expect(UnsupportedOperationException.class);
+    thrown.expectMessage("No support for arrays, etc.  Name was: [Ljava.lang.String;");
+    ns.getNode(s(new String[0].getClass()));
+  }
+
+  @Test
+  public void testRepeatConstructorArg() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Repeated constructor parameter detected.  Cannot inject constructor org.apache.reef.tang.implementation.RepeatConstructorArg(int,int)");
+    ns.getNode(s(RepeatConstructorArg.class));
+  }
+
+  @Test
+  public void testRepeatConstructorArgClasses() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Repeated constructor parameter detected.  Cannot inject constructor org.apache.reef.tang.implementation.RepeatConstructorArgClasses(org.apache.reef.tang.implementation.A,org.apache.reef.tang.implementation.A)");
+    ns.getNode(s(RepeatConstructorArgClasses.class));
+  }
+
+  @Test
+  public void testLeafRepeatedConstructorArgClasses() throws NameResolutionException {
+    ns.getNode(s(LeafRepeatedConstructorArgClasses.class));
+  }
+
+  @Test
+  public void testNamedRepeatConstructorArgClasses() throws NameResolutionException {
+    ns.getNode(s(NamedRepeatConstructorArgClasses.class));
+  }
+
+  @Test
+  public void testResolveDependencies() throws NameResolutionException {
+    ns.getNode(s(SimpleConstructors.class));
+    Assert.assertNotNull(ns.getNode(ReflectionUtilities
+        .getFullName(String.class)));
+  }
+
+  @Test
+  public void testDocumentedLocalNamedParameter() throws NameResolutionException {
+    ns.getNode(s(DocumentedLocalNamedParameter.class));
+  }
+
+  @Test
+  public void testNamedParameterTypeMismatch() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Named parameter type mismatch in org.apache.reef.tang.implementation.NamedParameterTypeMismatch.  Constructor expects a java.lang.String but Foo is a java.lang.Integer");
+    ns.getNode(s(NamedParameterTypeMismatch.class));
+  }
+
+  @Test
+  public void testUnannotatedName() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Named parameter org.apache.reef.tang.implementation.UnannotatedName is missing its @NamedParameter annotation.");
+    ns.getNode(s(UnannotatedName.class));
+  }
+
+  // TODO: The next three error messages should be more specific about the underlying cause of the failure.
+  @Test
+  public void testAnnotatedNotName() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Found illegal @NamedParameter org.apache.reef.tang.implementation.AnnotatedNotName does not implement Name<?>");
+    ns.getNode(s(AnnotatedNotName.class));
+  }
+
+  @Test
+  public void testAnnotatedNameWrongInterface() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Found illegal @NamedParameter org.apache.reef.tang.implementation.AnnotatedNameWrongInterface does not implement Name<?>");
+    ns.getNode(s(AnnotatedNameWrongInterface.class));
+  }
+
+  @Test
+  public void testAnnotatedNameNotGenericInterface() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Found illegal @NamedParameter org.apache.reef.tang.implementation.AnnotatedNameNotGenericInterface does not implement Name<?>");
+    ns.getNode(s(AnnotatedNameNotGenericInterface.class));
+  }
+
+  @Test
+  public void testAnnotatedNameMultipleInterfaces() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Named parameter org.apache.reef.tang.implementation.AnnotatedNameMultipleInterfaces implements multiple interfaces.  It is only allowed to implement Name<T>");
+    ns.getNode(s(AnnotatedNameMultipleInterfaces.class));
+  }
+
+  @Test
+  public void testUnAnnotatedNameMultipleInterfaces() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Named parameter org.apache.reef.tang.implementation.UnAnnotatedNameMultipleInterfaces is missing its @NamedParameter annotation.");
+    ns.getNode(s(UnAnnotatedNameMultipleInterfaces.class));
+  }
+
+  @Test
+  public void testNameWithConstructor() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Named parameter org.apache.reef.tang.implementation.NameWithConstructor has a constructor.  Named parameters must not declare any constructors.");
+    ns.getNode(s(NameWithConstructor.class));
+  }
+
+  @Test
+  public void testNameWithZeroArgInject() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Named parameter org.apache.reef.tang.implementation.NameWithZeroArgInject has an injectable constructor.  Named parameters must not declare any constructors.");
+    ns.getNode(s(NameWithZeroArgInject.class));
+  }
+
+  @Test
+  public void testGenericTorture1() throws NameResolutionException {
+    ns.getNode(s(GenericTorture1.class));
+  }
+
+  @Test
+  public void testGenericTorture2() throws NameResolutionException {
+    ns.getNode(s(GenericTorture2.class));
+  }
+
+  @Test
+  public void testGenericTorture3() throws NameResolutionException {
+    ns.getNode(s(GenericTorture3.class));
+  }
+
+  @Test
+  public void testGenericTorture4() throws NameResolutionException {
+    ns.getNode(s(GenericTorture4.class));
+  }
+
+  @Test
+  public void testGenericTorture5() throws NameResolutionException {
+    ns.getNode(s(GenericTorture5.class));
+  }
+
+  @Test
+  public void testGenericTorture6() throws NameResolutionException {
+    ns.getNode(s(GenericTorture6.class));
+  }
+
+  @Test
+  public void testGenericTorture7() throws NameResolutionException {
+    ns.getNode(s(GenericTorture7.class));
+  }
+
+  @Test
+  public void testGenericTorture8() throws NameResolutionException {
+    ns.getNode(s(GenericTorture8.class));
+  }
+
+  @Test
+  public void testGenericTorture9() throws NameResolutionException {
+    ns.getNode(s(GenericTorture9.class));
+  }
+
+  @Test
+  public void testGenericTorture10() throws NameResolutionException {
+    ns.getNode(s(GenericTorture10.class));
+  }
+
+  @Test
+  public void testGenericTorture11() throws NameResolutionException {
+    ns.getNode(s(GenericTorture11.class));
+  }
+
+  @Test
+  public void testGenericTorture12() throws NameResolutionException {
+    ns.getNode(s(GenericTorture12.class));
+  }
+
+  @Test
+  public void testInjectNonStaticLocalArgClass() throws NameResolutionException {
+    ns.getNode(s(InjectNonStaticLocalArgClass.class));
+  }
+
+  @Test(expected = ClassHierarchyException.class)
+  public void testInjectNonStaticLocalType() throws NameResolutionException {
+    ns.getNode(s(InjectNonStaticLocalType.class));
+  }
+
+  @Test(expected = ClassHierarchyException.class)
+  public void testConflictingShortNames() throws NameResolutionException {
+    ns.getNode(s(ShortNameFooA.class));
+    ns.getNode(s(ShortNameFooB.class));
+  }
+
+  @Test
+  public void testOKShortNames() throws NameResolutionException {
+    ns.getNode(s(ShortNameFooA.class));
+  }
+
+  @Test
+  public void testRoundTripInnerClassNames() throws ClassNotFoundException, NameResolutionException {
+    Node n = ns.getNode(s(Nested.Inner.class));
+    Class.forName(n.getFullName());
+  }
+
+  @Test
+  public void testRoundTripAnonInnerClassNames() throws ClassNotFoundException, NameResolutionException {
+    Node n = ns.getNode(s(AnonNested.x.getClass()));
+    Node m = ns.getNode(s(AnonNested.y.getClass()));
+    Assert.assertNotSame(n.getFullName(), m.getFullName());
+    Class<?> c = Class.forName(n.getFullName());
+    Class<?> d = Class.forName(m.getFullName());
+    Assert.assertNotSame(c, d);
+  }
+
+  @Test
+  public void testUnitIsInjectable() throws InjectionException, NameResolutionException {
+    ClassNode<?> n = (ClassNode<?>) ns.getNode(s(OuterUnitTH.class));
+    Assert.assertTrue(n.isUnit());
+    Assert.assertTrue(n.isInjectionCandidate());
+  }
+
+  @Test
+  public void testBadUnitDecl() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Detected explicit constructor in class enclosed in @Unit org.apache.reef.tang.implementation.OuterUnitBad$InA  Such constructors are disallowed.");
+
+    ns.getNode(s(OuterUnitBad.class));
+  }
+
+  @Test
+  public void nameCantBindWrongSubclassAsDefault() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("class org.apache.reef.tang.implementation.BadName defines a default class java.lang.Integer with a raw type that does not extend of its target's raw type class java.lang.String");
+
+    ns.getNode(s(BadName.class));
+  }
+
+  @Test
+  public void ifaceCantBindWrongImplAsDefault() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("interface org.apache.reef.tang.implementation.BadIfaceDefault declares its default implementation to be non-subclass class java.lang.String");
+    ns.getNode(s(BadIfaceDefault.class));
+  }
+
+  @Test
+  public void testParseableDefaultClassNotOK() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Named parameter org.apache.reef.tang.implementation.BadParsableDefaultClass defines default implementation for parsable type java.lang.String");
+    ns.getNode(s(BadParsableDefaultClass.class));
+  }
+
+  @Test
+  public void testDanglingUnit() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("Class org.apache.reef.tang.implementation.DanglingUnit has an @Unit annotation, but no non-static inner classes.  Such @Unit annotations would have no effect, and are therefore disallowed.");
+
+    ns.getNode(s(DanglingUnit.class));
+
+  }
+
+  @Test
+  public void testNonInjectableParam() throws NameResolutionException {
+    thrown.expect(ClassHierarchyException.class);
+    thrown.expectMessage("public org.apache.reef.tang.implementation.NonInjectableParam(int) is not injectable, but it has an @Parameter annotation.");
+    ns.getNode(s(NonInjectableParam.class));
+  }
+
+}
+
+@NamedParameter(default_class = String.class)
+class BadParsableDefaultClass implements Name<String> {
+}
+
+@NamedParameter(default_class = Integer.class)
+class BadName implements Name<String> {
+}
+
+class SimpleConstructors {
+
+  @Inject
+  public SimpleConstructors() {
+  }
+
+  @Inject
+  public SimpleConstructors(int x) {
+  }
+
+  public SimpleConstructors(String x) {
+  }
+
+  @Inject
+  public SimpleConstructors(int x, String y) {
+  }
+}
+
+class NamedParameterConstructors {
+
+  @Inject
+  public NamedParameterConstructors(String x, @Parameter(X.class) String y) {
+  }
+
+  ;
+
+  @NamedParameter()
+  class X implements Name<String> {
+  }
+}
+
+class RepeatConstructorArg {
+  public
+  @Inject
+  RepeatConstructorArg(int x, int y) {
+  }
+}
+
+class A {
+}
+
+class RepeatConstructorArgClasses {
+  public
+  @Inject
+  RepeatConstructorArgClasses(A x, A y) {
+  }
+}
+
+class LeafRepeatedConstructorArgClasses {
+
+  static class A {
+    class AA {
+    }
+  }
+
+  static class B {
+    class AA {
+    }
+  }
+
+  static class C {
+    @Inject
+    C(A.AA a, B.AA b) {
+    }
+  }
+}
+
+@NamedParameter()
+class AA implements Name<A> {
+}
+
+@NamedParameter()
+class BB implements Name<A> {
+}
+
+class NamedRepeatConstructorArgClasses {
+  public
+  @Inject
+  NamedRepeatConstructorArgClasses(@Parameter(AA.class) A x,
+                                   @Parameter(BB.class) A y) {
+  }
+}
+
+class DocumentedLocalNamedParameter {
+
+  @Inject
+  public DocumentedLocalNamedParameter(@Parameter(Foo.class) String s) {
+  }
+
+  @NamedParameter(doc = "doc stuff", default_value = "some value")
+  final class Foo implements Name<String> {
+  }
+}
+
+class NamedParameterTypeMismatch {
+
+  @Inject
+  public NamedParameterTypeMismatch(@Parameter(Foo.class) String s) {
+  }
+
+  @NamedParameter(doc = "doc.stuff", default_value = "1")
+  final class Foo implements Name<Integer> {
+  }
+}
+
+class UnannotatedName implements Name<String> {
+}
+
+@NamedParameter(doc = "c")
+class AnnotatedNotName {
+}
+
+@NamedParameter(doc = "c")
+class AnnotatedNameWrongInterface implements I1 {
+}
+
+@SuppressWarnings("rawtypes")
+@NamedParameter(doc = "c")
+class AnnotatedNameNotGenericInterface implements Name {
+}
+
+class UnAnnotatedNameMultipleInterfaces implements Name<Object>, I1 {
+}
+
+@NamedParameter(doc = "c")
+class AnnotatedNameMultipleInterfaces implements Name<Object>, I1 {
+}
+
+@NamedParameter()
+class NameWithConstructor implements Name<Object> {
+  private NameWithConstructor(int i) {
+  }
+}
+
+@NamedParameter()
+class NameWithZeroArgInject implements Name<Object> {
+  @Inject
+  public NameWithZeroArgInject() {
+  }
+}
+
+@NamedParameter()
+class GenericTorture1 implements Name<Set<String>> {
+}
+
+@NamedParameter()
+class GenericTorture2 implements Name<Set<?>> {
+}
+
+@NamedParameter()
+class GenericTorture3 implements Name<Set<Set<String>>> {
+}
+
+@SuppressWarnings("rawtypes")
+@NamedParameter()
+class GenericTorture4 implements Name<Set<Set>> {
+}
+
+@NamedParameter()
+class GenericTorture5 implements Name<Map<Set<String>, Set<String>>> {
+}
+
+@SuppressWarnings("rawtypes")
+@NamedParameter()
+class GenericTorture6 implements Name<Map<Set, Set<String>>> {
+}
+
+@SuppressWarnings("rawtypes")
+@NamedParameter()
+class GenericTorture7 implements Name<Map<Set<String>, Set>> {
+}
+
+@NamedParameter()
+class GenericTorture8 implements Name<Map<String, String>> {
+}
+
+@SuppressWarnings("rawtypes")
+@NamedParameter()
+class GenericTorture9 implements Name<Map<Set, Set>> {
+}
+
+@NamedParameter()
+class GenericTorture10 implements Name<List<String>> {
+}
+
+@NamedParameter()
+class GenericTorture11 implements Name<List<?>> {
+}
+
+@NamedParameter()
+class GenericTorture12 implements Name<List<List<String>>> {
+}
+
+class InjectNonStaticLocalArgClass {
+  @Inject
+  InjectNonStaticLocalArgClass(NonStaticLocal x) {
+  }
+
+  class NonStaticLocal {
+  }
+}
+
+class InjectNonStaticLocalType {
+  class NonStaticLocal {
+    @Inject
+    NonStaticLocal(NonStaticLocal x) {
+    }
+  }
+}
+
+@NamedParameter(short_name = "foo")
+class ShortNameFooA implements Name<String> {
+}
+
+@NamedParameter(short_name = "foo")
+class ShortNameFooB implements Name<Integer> {
+}
+
+class Nested {
+  class Inner {
+  }
+}
+
+class AnonNested {
+  static X x = new X() {
+    @SuppressWarnings("unused")
+    int i;
+  };
+  static X y = new X() {
+    @SuppressWarnings("unused")
+    int j;
+  };
+
+  static interface X {
+  }
+}
+
+@Unit
+class OuterUnitBad {
+  class InA {
+    @Inject
+    InA() {
+    }
+  }
+
+  class InB {
+  }
+}
+
+@Unit
+class OuterUnitTH {
+  class InA {
+  }
+
+  class InB {
+  }
+}
+
+@Unit
+class DanglingUnit {
+  @Inject
+  DanglingUnit() {
+  }
+
+  static class DoesntCount {
+  }
+}
+
+class SomeName implements Name<Integer> {
+}
+
+class NonInjectableParam {
+  public NonInjectableParam(@Parameter(SomeName.class) int i) {
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestConfigurationBuilder.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestConfigurationBuilder.java
new file mode 100644
index 0000000..7a65cd3
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestConfigurationBuilder.java
@@ -0,0 +1,60 @@
+/**
+ * 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.java;
+
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+import org.apache.reef.tang.annotations.Parameter;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javax.inject.Inject;
+
+/**
+ * TestConfigurationBuilder
+ */
+public class TestConfigurationBuilder {
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void nullStringVaueTest() {
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("The value null set to the named parameter is illegal: class org.apache.reef.tang.implementation.java.TestConfigurationBuilder$NamedParamterNoDefault$NamedString");
+
+    Tang.Factory.getTang().newConfigurationBuilder()
+        .bindNamedParameter(NamedParamterNoDefault.NamedString.class, (String) null)
+        .build();
+  }
+
+  static class NamedParamterNoDefault {
+    final private String str;
+
+    @Inject
+    NamedParamterNoDefault(@Parameter(NamedString.class) String str) {
+      this.str = str;
+    }
+
+    @NamedParameter()
+    class NamedString implements Name<String> {
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestParameterParser.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestParameterParser.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestParameterParser.java
new file mode 100644
index 0000000..0425920
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/java/TestParameterParser.java
@@ -0,0 +1,245 @@
+/**
+ * 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.java;
+
+import org.apache.reef.tang.ExternalConstructor;
+import org.apache.reef.tang.JavaConfigurationBuilder;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+import org.apache.reef.tang.annotations.Parameter;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.InjectionException;
+import org.apache.reef.tang.formats.ParameterParser;
+import org.apache.reef.tang.util.ReflectionUtilities;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javax.inject.Inject;
+
+public class TestParameterParser {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void testParameterParser() throws BindException {
+    ParameterParser p = new ParameterParser();
+    p.addParser(FooParser.class);
+    Foo f = p.parse(Foo.class, "woot");
+    Assert.assertEquals(f.s, "woot");
+  }
+
+  @Test
+  public void testUnregisteredParameterParser() throws BindException {
+    thrown.expect(UnsupportedOperationException.class);
+    thrown.expectMessage("Don't know how to parse a org.apache.reef.tang.implementation.java.TestParameterParser$Foo");
+    ParameterParser p = new ParameterParser();
+    //p.addParser(FooParser.class);
+    Foo f = p.parse(Foo.class, "woot");
+    Assert.assertEquals(f.s, "woot");
+  }
+
+  @Test
+  public void testReturnSubclass() throws BindException {
+    ParameterParser p = new ParameterParser();
+    p.addParser(BarParser.class);
+    Bar f = (Bar) p.parse(Foo.class, "woot");
+    Assert.assertEquals(f.s, "woot");
+
+  }
+
+  @Test
+  public void testGoodMerge() throws BindException {
+    ParameterParser old = new ParameterParser();
+    old.addParser(BarParser.class);
+    ParameterParser nw = new ParameterParser();
+    nw.mergeIn(old);
+    nw.parse(Foo.class, "woot");
+  }
+
+  @Test
+  public void testGoodMerge2() throws BindException {
+    ParameterParser old = new ParameterParser();
+    old.addParser(BarParser.class);
+    ParameterParser nw = new ParameterParser();
+    nw.addParser(BarParser.class);
+    nw.mergeIn(old);
+    nw.parse(Foo.class, "woot");
+  }
+
+  @Test
+  public void testBadMerge() throws BindException {
+    thrown.expect(IllegalArgumentException.class);
+    thrown.expectMessage("Conflict detected when merging parameter parsers! To parse org.apache.reef.tang.implementation.java.TestParameterParser$Foo I have a: org.apache.reef.tang.implementation.java.TestParameterParser$FooParser the other instance has a: org.apache.reef.tang.implementation.java.TestParameterParser$BarParser");
+    ParameterParser old = new ParameterParser();
+    old.addParser(BarParser.class);
+    ParameterParser nw = new ParameterParser();
+    nw.addParser(FooParser.class);
+    nw.mergeIn(old);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  public void testEndToEnd() throws BindException, InjectionException {
+    Tang tang = Tang.Factory.getTang();
+    JavaConfigurationBuilder cb = tang.newConfigurationBuilder(BarParser.class);
+    cb.bindNamedParameter(SomeNamedFoo.class, "hdfs://woot");
+    ILikeBars ilb = tang.newInjector(cb.build()).getInstance(ILikeBars.class);
+    Assert.assertNotNull(ilb);
+  }
+
+  @SuppressWarnings("unchecked")
+  @Test
+  public void testDelegatingParser() throws BindException, InjectionException, ClassNotFoundException {
+    Tang tang = Tang.Factory.getTang();
+    JavaConfigurationBuilder cb = tang.newConfigurationBuilder(TypeParser.class);
+
+    JavaConfigurationBuilder cb2 = tang.newConfigurationBuilder(cb.build());
+
+    cb2.bind(ReflectionUtilities.getFullName(ParseName.class), "a");
+
+    ParseableType t = tang.newInjector(cb2.build()).getNamedInstance(ParseName.class);
+    Assert.assertTrue(t instanceof ParseTypeA);
+
+    cb2 = tang.newConfigurationBuilder(cb.build());
+
+    cb2.bind(ReflectionUtilities.getFullName(ParseNameB.class), "b");
+    cb2.bindNamedParameter(ParseNameA.class, "a");
+    tang.newInjector(cb2.build()).getInstance(NeedsA.class);
+    tang.newInjector(cb2.build()).getInstance(NeedsB.class);
+
+  }
+
+  private static class FooParser implements ExternalConstructor<Foo> {
+    private final Foo foo;
+
+    @Inject
+    public FooParser(String s) {
+      this.foo = new Foo(s);
+    }
+
+    @Override
+    public Foo newInstance() {
+      return foo;
+    }
+  }
+
+  private static class BarParser implements ExternalConstructor<Foo> {
+    private final Bar bar;
+
+    @Inject
+    public BarParser(String s) {
+      this.bar = new Bar(s);
+    }
+
+    @Override
+    public Bar newInstance() {
+      return bar;
+    }
+  }
+
+  private static class Foo {
+    public final String s;
+
+    public Foo(String s) {
+      this.s = s;
+    }
+  }
+
+  private static class Bar extends Foo {
+    public Bar(String s) {
+      super(s);
+    }
+  }
+
+  @NamedParameter
+  private static class SomeNamedFoo implements Name<Foo> {
+  }
+
+  private static class ILikeBars {
+    @Inject
+    ILikeBars(@Parameter(SomeNamedFoo.class) Foo bar) {
+      Bar b = (Bar) bar;
+      Assert.assertEquals(b.s, "hdfs://woot");
+    }
+  }
+
+  private static class ParseableType {
+  }
+
+  private static class ParseTypeA extends ParseableType {
+
+  }
+
+  private static class ParseTypeB extends ParseableType {
+
+  }
+
+  private static class TypeParser implements ExternalConstructor<ParseableType> {
+    ParseableType instance;
+
+    @Inject
+    public TypeParser(String s) {
+      if (s.equals("a")) {
+        instance = new ParseTypeA();
+      }
+      if (s.equals("b")) {
+        instance = new ParseTypeB();
+      }
+
+    }
+
+    @Override
+    public ParseableType newInstance() {
+      return instance;
+    }
+  }
+
+  @NamedParameter()
+  private static class ParseName implements Name<ParseableType> {
+
+  }
+
+  @NamedParameter()
+  private static class ParseNameA implements Name<ParseableType> {
+
+  }
+
+  @NamedParameter()
+  private static class ParseNameB implements Name<ParseTypeB> {
+
+  }
+
+  private static class NeedsA {
+    @Inject
+    public NeedsA(@Parameter(ParseNameA.class) ParseableType a) {
+      Assert.assertTrue(a instanceof ParseTypeA);
+    }
+  }
+
+  private static class NeedsB {
+    @Inject
+    public NeedsB(@Parameter(ParseNameB.class) ParseTypeB b) {
+      Assert.assertTrue(b instanceof ParseTypeB);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/protobuf/TestClassHierarchyRoundTrip.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/protobuf/TestClassHierarchyRoundTrip.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/protobuf/TestClassHierarchyRoundTrip.java
new file mode 100644
index 0000000..238f979
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/implementation/protobuf/TestClassHierarchyRoundTrip.java
@@ -0,0 +1,401 @@
+/**
+ * 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.protobuf;
+
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.exceptions.InjectionException;
+import org.apache.reef.tang.exceptions.NameResolutionException;
+import org.apache.reef.tang.implementation.TangImpl;
+import org.apache.reef.tang.implementation.TestClassHierarchy;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+public class TestClassHierarchyRoundTrip extends TestClassHierarchy {
+
+  private void setup1() {
+    TangImpl.reset();
+    ns = Tang.Factory.getTang().getDefaultClassHierarchy();
+  }
+
+  private void setup2() {
+    TangImpl.reset();
+    ns = new ProtocolBufferClassHierarchy(ProtocolBufferClassHierarchy.serialize(ns));
+  }
+
+  private void setup3() {
+    TangImpl.reset();
+    try {
+      final File file = java.io.File.createTempFile("testProto", "bin");
+      ProtocolBufferClassHierarchy.serialize(file, ns);
+      ns = ProtocolBufferClassHierarchy.deserialize(file);
+      file.delete();
+    } catch (IOException e) {
+      Assert.fail(String.format("IOException when serialize/deserialize proto buffer file ", e));
+    }
+  }
+
+  @Test
+  @Override
+  public void testJavaString() throws NameResolutionException {
+    setup1();
+    super.testJavaString();
+    setup2();
+    super.testJavaString();
+    setup3();
+    super.testJavaString();
+  }
+
+  @Test
+  @Override
+  public void testSimpleConstructors() throws NameResolutionException {
+    setup1();
+    super.testSimpleConstructors();
+    setup2();
+    super.testSimpleConstructors();
+    setup3();
+    super.testSimpleConstructors();
+  }
+
+  @Test
+  @Override
+  public void testNamedParameterConstructors() throws NameResolutionException {
+    setup1();
+    super.testNamedParameterConstructors();
+    setup2();
+    super.testNamedParameterConstructors();
+    setup3();
+    super.testNamedParameterConstructors();
+  }
+
+  @Test
+  @Override
+  public void testArray() throws NameResolutionException {
+    setup1();
+    super.testArray();
+    setup2();
+    super.testArray();
+    setup3();
+    super.testArray();
+  }
+
+  @Test
+  @Override
+  public void testRepeatConstructorArg() throws NameResolutionException {
+    setup1();
+    super.testRepeatConstructorArg();
+    setup2();
+    super.testRepeatConstructorArg();
+    setup3();
+    super.testRepeatConstructorArg();
+  }
+
+  @Test
+  @Override
+  public void testRepeatConstructorArgClasses() throws NameResolutionException {
+    setup1();
+    super.testRepeatConstructorArgClasses();
+    setup2();
+    super.testRepeatConstructorArgClasses();
+    setup3();
+    super.testRepeatConstructorArgClasses();
+  }
+
+  @Test
+  @Override
+  public void testLeafRepeatedConstructorArgClasses() throws NameResolutionException {
+    setup1();
+    super.testLeafRepeatedConstructorArgClasses();
+    setup2();
+    super.testLeafRepeatedConstructorArgClasses();
+    setup3();
+    super.testLeafRepeatedConstructorArgClasses();
+  }
+
+  @Test
+  @Override
+  public void testNamedRepeatConstructorArgClasses() throws NameResolutionException {
+    setup1();
+    super.testNamedRepeatConstructorArgClasses();
+    setup2();
+    super.testNamedRepeatConstructorArgClasses();
+    setup3();
+    super.testNamedRepeatConstructorArgClasses();
+  }
+
+  @Test
+  @Override
+  public void testResolveDependencies() throws NameResolutionException {
+    setup1();
+    super.testResolveDependencies();
+    setup2();
+    super.testResolveDependencies();
+    setup3();
+    super.testResolveDependencies();
+  }
+
+  @Test
+  @Override
+  public void testDocumentedLocalNamedParameter() throws NameResolutionException {
+    setup1();
+    super.testDocumentedLocalNamedParameter();
+    setup2();
+    super.testDocumentedLocalNamedParameter();
+    setup3();
+    super.testDocumentedLocalNamedParameter();
+  }
+
+  @Test
+  @Override
+  public void testNamedParameterTypeMismatch() throws NameResolutionException {
+    setup1();
+    super.testNamedParameterTypeMismatch();
+    setup2();
+    super.testNamedParameterTypeMismatch();
+    setup3();
+    super.testNamedParameterTypeMismatch();
+  }
+
+  @Test
+  @Override
+  public void testUnannotatedName() throws NameResolutionException {
+    setup1();
+    super.testUnannotatedName();
+    setup2();
+    super.testUnannotatedName();
+    setup3();
+    super.testUnannotatedName();
+  }
+
+  @Test
+  @Override
+  public void testAnnotatedNotName() throws NameResolutionException {
+    setup1();
+    super.testAnnotatedNotName();
+    setup2();
+    super.testAnnotatedNotName();
+    setup3();
+    super.testAnnotatedNotName();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture1() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture1();
+    setup2();
+    super.testGenericTorture1();
+    setup3();
+    super.testGenericTorture1();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture2() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture2();
+    setup2();
+    super.testGenericTorture2();
+    setup3();
+    super.testGenericTorture2();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture3() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture3();
+    setup2();
+    super.testGenericTorture3();
+    setup3();
+    super.testGenericTorture3();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture4() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture4();
+    setup2();
+    super.testGenericTorture4();
+    setup3();
+    super.testGenericTorture4();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture5() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture5();
+    setup2();
+    super.testGenericTorture5();
+    setup3();
+    super.testGenericTorture5();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture6() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture6();
+    setup2();
+    super.testGenericTorture6();
+    setup3();
+    super.testGenericTorture6();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture7() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture7();
+    setup2();
+    super.testGenericTorture7();
+    setup3();
+    super.testGenericTorture7();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture8() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture8();
+    setup2();
+    super.testGenericTorture8();
+    setup3();
+    super.testGenericTorture8();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture9() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture9();
+    setup2();
+    super.testGenericTorture9();
+    setup3();
+    super.testGenericTorture9();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture10() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture10();
+    setup2();
+    super.testGenericTorture10();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture11() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture11();
+    setup2();
+    super.testGenericTorture11();
+  }
+
+  @Test
+  @Override
+  public void testGenericTorture12() throws NameResolutionException {
+    setup1();
+    super.testGenericTorture12();
+    setup2();
+    super.testGenericTorture12();
+  }
+
+  @Test
+  @Override
+  public void testInjectNonStaticLocalArgClass() throws NameResolutionException {
+    setup1();
+    super.testInjectNonStaticLocalArgClass();
+    setup2();
+    super.testInjectNonStaticLocalArgClass();
+    setup3();
+    super.testInjectNonStaticLocalArgClass();
+  }
+
+  @Test
+  @Override
+  public void testOKShortNames() throws NameResolutionException {
+    setup1();
+    super.testOKShortNames();
+    setup2();
+    super.testOKShortNames();
+    setup3();
+    super.testOKShortNames();
+  }
+
+  @Test
+  @Override
+  public void testRoundTripInnerClassNames() throws NameResolutionException, ClassNotFoundException {
+    setup1();
+    super.testRoundTripInnerClassNames();
+    setup2();
+    super.testRoundTripInnerClassNames();
+    setup3();
+    super.testRoundTripInnerClassNames();
+  }
+
+  @Test
+  @Override
+  public void testUnitIsInjectable() throws NameResolutionException, InjectionException {
+    setup1();
+    super.testUnitIsInjectable();
+    setup2();
+    super.testUnitIsInjectable();
+    setup3();
+    super.testUnitIsInjectable();
+  }
+
+  @Test
+  @Override
+  public void testBadUnitDecl() throws NameResolutionException {
+    setup1();
+    super.testBadUnitDecl();
+    setup2();
+    super.testBadUnitDecl();
+    setup3();
+    super.testBadUnitDecl();
+  }
+
+  @Test
+  @Override
+  public void nameCantBindWrongSubclassAsDefault() throws NameResolutionException {
+    setup1();
+    super.nameCantBindWrongSubclassAsDefault();
+    setup2();
+    super.nameCantBindWrongSubclassAsDefault();
+    setup3();
+    super.nameCantBindWrongSubclassAsDefault();
+  }
+
+  @Test
+  @Override
+  public void ifaceCantBindWrongImplAsDefault() throws NameResolutionException {
+    setup1();
+    super.ifaceCantBindWrongImplAsDefault();
+    setup2();
+    super.ifaceCantBindWrongImplAsDefault();
+    setup3();
+    super.ifaceCantBindWrongImplAsDefault();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterface.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterface.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterface.java
new file mode 100644
index 0000000..6d6b6d6
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterface.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.test;
+
+import org.apache.reef.tang.annotations.DefaultImplementation;
+
+/**
+ * An interface with a default implementation
+ */
+@DefaultImplementation(AnInterfaceImplementation.class)
+interface AnInterface {
+  void aMethod();
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterfaceImplementation.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterfaceImplementation.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterfaceImplementation.java
new file mode 100644
index 0000000..d932b37
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/AnInterfaceImplementation.java
@@ -0,0 +1,52 @@
+/**
+ * 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.test;
+
+import javax.inject.Inject;
+
+final class AnInterfaceImplementation implements AnInterface {
+  private final int aMagicNumber;
+
+  @Inject
+  AnInterfaceImplementation() {
+    this.aMagicNumber = 42;
+  }
+
+  @Override
+  public void aMethod() {
+
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    AnInterfaceImplementation that = (AnInterfaceImplementation) o;
+
+    if (aMagicNumber != that.aMagicNumber) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return aMagicNumber;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependency.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependency.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependency.java
new file mode 100644
index 0000000..ca48643
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependency.java
@@ -0,0 +1,56 @@
+/**
+ * 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.test;
+
+import javax.inject.Inject;
+
+/**
+ * Part of a cyclic dependency
+ */
+final class CyclicDependency {
+  private final CyclicDependencyClassOne one;
+  private final CyclicDependencyClassTwo two;
+
+  @Inject
+  CyclicDependency(final CyclicDependencyClassOne one,
+                   final CyclicDependencyClassTwo two) {
+    this.one = one;
+    this.two = two;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    CyclicDependency that = (CyclicDependency) o;
+
+    if (!one.equals(that.one)) return false;
+    if (!two.equals(that.two)) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = one.hashCode();
+    result = 31 * result + two.hashCode();
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassOne.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassOne.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassOne.java
new file mode 100644
index 0000000..513a854
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassOne.java
@@ -0,0 +1,50 @@
+/**
+ * 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.test;
+
+import javax.inject.Inject;
+
+/**
+ * Part of a cyclic dependency
+ */
+final class CyclicDependencyClassOne {
+  private final CyclicDependencyClassTwo other;
+
+  @Inject
+  CyclicDependencyClassOne(final CyclicDependencyClassTwo other) {
+    this.other = other;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    CyclicDependencyClassOne that = (CyclicDependencyClassOne) o;
+
+    if (!other.equals(that.other)) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return other.hashCode();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassTwo.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassTwo.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassTwo.java
new file mode 100644
index 0000000..bfceb55
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/CyclicDependencyClassTwo.java
@@ -0,0 +1,48 @@
+/**
+ * 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.test;
+
+import org.apache.reef.tang.InjectionFuture;
+
+import javax.inject.Inject;
+
+/**
+ * Part of a cyclic dependency.
+ */
+final class CyclicDependencyClassTwo {
+  private final InjectionFuture<CyclicDependencyClassOne> other;
+
+  @Inject
+  CyclicDependencyClassTwo(InjectionFuture<CyclicDependencyClassOne> other) {
+    this.other = other;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return other.hashCode();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/Handler.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/Handler.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/Handler.java
new file mode 100644
index 0000000..864b362
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/Handler.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.test;
+
+/**
+ * An interface with a type parameter. This can be found e.g. in REEF EventHandlers.
+ *
+ * @param <T>
+ */
+interface Handler<T> {
+
+  public void process(final T value);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/InjectableClass.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/InjectableClass.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/InjectableClass.java
new file mode 100644
index 0000000..a8accb8
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/InjectableClass.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.test;
+
+import javax.inject.Inject;
+
+final class InjectableClass {
+
+  private final int magicNumber = -42;
+
+  @Inject
+  InjectableClass() {
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    InjectableClass that = (InjectableClass) o;
+
+    if (magicNumber != that.magicNumber) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return magicNumber;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterface.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterface.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterface.java
new file mode 100644
index 0000000..4e8c1a0
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterface.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.test;
+
+public interface ListInterface {
+  void bMethod();
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplOne.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplOne.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplOne.java
new file mode 100644
index 0000000..3adad54
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplOne.java
@@ -0,0 +1,55 @@
+/**
+ * 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.test;
+
+import javax.inject.Inject;
+
+public class ListInterfaceImplOne implements ListInterface {
+
+  private final int magicNumber;
+
+  @Inject
+  ListInterfaceImplOne() {
+    magicNumber = 31;
+  }
+
+  @Override
+  public void bMethod() {
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    } else if (obj == null || obj.getClass() != getClass()) {
+      return false;
+    } else {
+      ListInterfaceImplOne one = (ListInterfaceImplOne) obj;
+      if (one.magicNumber != magicNumber) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  @Override
+  public int hashCode() {
+    return magicNumber;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplTwo.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplTwo.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplTwo.java
new file mode 100644
index 0000000..1513f82
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListInterfaceImplTwo.java
@@ -0,0 +1,55 @@
+/**
+ * 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.test;
+
+import javax.inject.Inject;
+
+public class ListInterfaceImplTwo implements ListInterface {
+  private final double magicNumber;
+
+  @Inject
+  ListInterfaceImplTwo() {
+    magicNumber = 31.0;
+  }
+
+  @Override
+  public void bMethod() {
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) {
+      return true;
+    } else if (obj == null || obj.getClass() != getClass()) {
+      return false;
+    } else {
+      ListInterfaceImplTwo two = (ListInterfaceImplTwo) obj;
+      if (Double.compare(two.magicNumber, magicNumber) != 0) {
+        return false;
+      }
+      return true;
+    }
+  }
+
+  @Override
+  public int hashCode() {
+    long temp = Double.doubleToLongBits(magicNumber);
+    return (int) (temp ^ (temp >>> 32));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfBaseTypes.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfBaseTypes.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfBaseTypes.java
new file mode 100644
index 0000000..76d0a26
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfBaseTypes.java
@@ -0,0 +1,82 @@
+/**
+ * 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.test;
+
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+import org.apache.reef.tang.annotations.Parameter;
+
+import javax.inject.Inject;
+import java.util.List;
+
+final class ListOfBaseTypes {
+  private final List<Integer> integers;
+  private final List<Double> doubles;
+  private final List<String> strings;
+  private final List<Integer> moreIntegers;
+
+  @Inject
+  ListOfBaseTypes(@Parameter(Integers.class) final List<Integer> integers,
+                  @Parameter(Doubles.class) final List<Double> doubles,
+                  @Parameter(Strings.class) final List<String> strings,
+                  @Parameter(MoreIntegers.class) final List<Integer> moreIntegers) {
+    this.integers = integers;
+    this.doubles = doubles;
+    this.strings = strings;
+    this.moreIntegers = moreIntegers;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ListOfBaseTypes that = (ListOfBaseTypes) o;
+
+    if (!doubles.equals(that.doubles)) return false;
+    if (!integers.equals(that.integers)) return false;
+    if (!strings.equals(that.strings)) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result = integers.hashCode();
+    result = 31 * result + doubles.hashCode();
+    result = 31 * result + strings.hashCode();
+    return result;
+  }
+
+  @NamedParameter
+  public static class Integers implements Name<List<Integer>> {
+  }
+
+  @NamedParameter(default_values = {"1", "2", "3"})
+  public static class MoreIntegers implements Name<List<Integer>> {
+  }
+
+  @NamedParameter
+  public static class Doubles implements Name<List<Double>> {
+  }
+
+  @NamedParameter
+  public static class Strings implements Name<List<String>> {
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfImplementations.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfImplementations.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfImplementations.java
new file mode 100644
index 0000000..c1fc103
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ListOfImplementations.java
@@ -0,0 +1,55 @@
+/**
+ * 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.test;
+
+import org.apache.reef.tang.annotations.Parameter;
+
+import javax.inject.Inject;
+import java.util.List;
+
+public class ListOfImplementations {
+
+  private final List<ListInterface> theInstances;
+
+  @Inject
+  ListOfImplementations(@Parameter(TestConfiguration.ListOfInstances.class) final List<ListInterface> theInstances) {
+    this.theInstances = theInstances;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    ListOfImplementations that = (ListOfImplementations) o;
+
+    if (!theInstances.equals(that.theInstances)) return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    return theInstances.hashCode();
+  }
+
+  public boolean isValid() {
+    return this.theInstances.size() == 2;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ObjectTreeTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ObjectTreeTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ObjectTreeTest.java
new file mode 100644
index 0000000..53fb0ec
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/ObjectTreeTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.test;
+
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.InjectionException;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ObjectTreeTest {
+
+  public static Configuration getConfiguration() throws BindException {
+    return TestConfiguration.CONF
+        .set(TestConfiguration.OPTIONAL_STRING, TestConfiguration.OPTIONAL_STRING_VALUE)
+        .set(TestConfiguration.REQUIRED_STRING, TestConfiguration.REQUIRED_STRING_VALUE)
+        .build();
+  }
+
+  /**
+   * Configuration getter for TestConfigurationWithoutList.
+   */
+  public static Configuration getConfigurationWithoutList() throws BindException {
+    // TODO: Remove this method after #192 is fixed
+    return TestConfigurationWithoutList.CONF
+        .set(TestConfigurationWithoutList.OPTIONAL_STRING, TestConfigurationWithoutList.OPTIONAL_STRING_VALUE)
+        .set(TestConfigurationWithoutList.REQUIRED_STRING, TestConfigurationWithoutList.REQUIRED_STRING_VALUE)
+        .build();
+  }
+
+  @Test
+  public void testInstantiation() throws BindException, InjectionException {
+    final RootInterface root = Tang.Factory.getTang().newInjector(getConfiguration()).getInstance(RootInterface.class);
+    Assert.assertTrue("Object instantiation left us in an inconsistent state.", root.isValid());
+  }
+
+  @Test
+  public void testTwoInstantiations() throws BindException, InjectionException {
+    final RootInterface firstRoot = Tang.Factory.getTang().newInjector(getConfiguration()).getInstance(RootInterface.class);
+    final RootInterface secondRoot = Tang.Factory.getTang().newInjector(getConfiguration()).getInstance(RootInterface.class);
+    Assert.assertNotSame("Two instantiations of the object tree should not be the same", firstRoot, secondRoot);
+    Assert.assertEquals("Two instantiations of the object tree should be equal", firstRoot, secondRoot);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementation.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementation.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementation.java
new file mode 100644
index 0000000..161eb67
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementation.java
@@ -0,0 +1,166 @@
+/**
+ * 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.test;
+
+
+import org.apache.reef.tang.annotations.Parameter;
+
+import javax.inject.Inject;
+
+/**
+ * The root of the object graph instantiated.
+ */
+final class RootImplementation implements RootInterface {
+
+  private final String requiredString;
+  private final String optionalString;
+  private final UnitClass unit;
+  private final Handler<String> stringHandler;
+  private final Handler<Integer> integerHandler;
+  private final AnInterface anInterface;
+  private final int anInt;
+  private final double aDouble;
+  private final InjectableClass injectableClass;
+  private final SetOfImplementations setOfImplementations;
+  private final SetOfBaseTypes setOfBaseTypes;
+  private final ListOfImplementations listOfImplementations;
+  private final ListOfBaseTypes listOfBaseTypes;
+  private final CyclicDependency cyclicDependency;
+
+  @Inject
+  public RootImplementation(@Parameter(TestConfiguration.RequiredString.class) final String requiredString,
+                            @Parameter(TestConfiguration.OptionalString.class) final String optionalString,
+                            @Parameter(TestConfiguration.StringHandler.class) final Handler<String> stringHandler,
+                            @Parameter(TestConfiguration.IntegerHandler.class) final Handler<Integer> integerHandler,
+                            @Parameter(TestConfiguration.NamedParameterInteger.class) final int anInt,
+                            @Parameter(TestConfiguration.NamedParameterDouble.class) double aDouble,
+                            final UnitClass unit,
+                            final AnInterface anInterface,
+                            final InjectableClass injectableClass,
+                            final SetOfImplementations setOfImplementations,
+                            final SetOfBaseTypes setOfBaseTypes,
+                            final ListOfImplementations listOfImplementations,
+                            final ListOfBaseTypes listOfBaseTypes,
+                            CyclicDependency cyclicDependency) {
+    this.requiredString = requiredString;
+    this.optionalString = optionalString;
+    this.unit = unit;
+    this.stringHandler = stringHandler;
+    this.integerHandler = integerHandler;
+    this.anInterface = anInterface;
+    this.anInt = anInt;
+    this.aDouble = aDouble;
+    this.injectableClass = injectableClass;
+    this.setOfImplementations = setOfImplementations;
+    this.setOfBaseTypes = setOfBaseTypes;
+    this.listOfImplementations = listOfImplementations;
+    this.listOfBaseTypes = listOfBaseTypes;
+    this.cyclicDependency = cyclicDependency;
+  }
+
+  @Override
+  public boolean isValid() {
+    if (!this.setOfImplementations.isValid()) {
+      return false;
+    }
+    if (!this.listOfImplementations.isValid()) {
+      return false;
+    }
+    if (!this.requiredString.equals(TestConfiguration.REQUIRED_STRING_VALUE)) {
+      return false;
+    }
+
+    if (!this.optionalString.equals(TestConfiguration.OPTIONAL_STRING_VALUE)) {
+      return false;
+    }
+
+    this.integerHandler.process(3);
+    this.stringHandler.process("three");
+    if (this.unit.getIntValue() != 3) {
+      return false;
+    }
+    if (!this.unit.getStringValue().equals("three")) {
+      return false;
+    }
+    if (this.anInterface == null) {
+      return false;
+    }
+
+    if (this.aDouble != TestConfiguration.NAMED_PARAMETER_DOUBLE_VALUE) {
+      return false;
+    }
+    if (this.anInt != TestConfiguration.NAMED_PARAMETER_INTEGER_VALUE) {
+      return false;
+    }
+
+    return true;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    RootImplementation that = (RootImplementation) o;
+
+    if (Double.compare(that.aDouble, aDouble) != 0) return false;
+    if (anInt != that.anInt) return false;
+    if (anInterface != null ? !anInterface.equals(that.anInterface) : that.anInterface != null) return false;
+    if (integerHandler != null ? !integerHandler.equals(that.integerHandler) : that.integerHandler != null)
+      return false;
+    if (optionalString != null ? !optionalString.equals(that.optionalString) : that.optionalString != null)
+      return false;
+    if (requiredString != null ? !requiredString.equals(that.requiredString) : that.requiredString != null)
+      return false;
+    if (stringHandler != null ? !stringHandler.equals(that.stringHandler) : that.stringHandler != null) return false;
+    if (unit != null ? !unit.equals(that.unit) : that.unit != null) return false;
+    if (injectableClass != null ? !injectableClass.equals(that.injectableClass) : that.injectableClass != null)
+      return false;
+    if (setOfImplementations != null ? !setOfImplementations.equals(that.setOfImplementations) : that.setOfImplementations != null)
+      return false;
+    if (setOfBaseTypes != null ? !setOfBaseTypes.equals(that.setOfBaseTypes) : that.setOfBaseTypes != null)
+      return false;
+    if (listOfImplementations != null ? !listOfImplementations.equals(that.listOfImplementations) : that
+        .listOfImplementations != null)
+      return false;
+    if (listOfBaseTypes != null ? !listOfBaseTypes.equals(that.listOfBaseTypes) : that.listOfBaseTypes != null)
+      return false;
+    if (cyclicDependency != null ? !cyclicDependency.equals(that.cyclicDependency) : that.cyclicDependency != null)
+      return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result;
+    long temp;
+    result = requiredString != null ? requiredString.hashCode() : 0;
+    result = 31 * result + (optionalString != null ? optionalString.hashCode() : 0);
+    result = 31 * result + (unit != null ? unit.hashCode() : 0);
+    result = 31 * result + (stringHandler != null ? stringHandler.hashCode() : 0);
+    result = 31 * result + (integerHandler != null ? integerHandler.hashCode() : 0);
+    result = 31 * result + (anInterface != null ? anInterface.hashCode() : 0);
+    result = 31 * result + anInt;
+    temp = Double.doubleToLongBits(aDouble);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementationWithoutList.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementationWithoutList.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementationWithoutList.java
new file mode 100644
index 0000000..6569b19
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootImplementationWithoutList.java
@@ -0,0 +1,155 @@
+/**
+ * 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.test;
+
+import org.apache.reef.tang.annotations.Parameter;
+
+import javax.inject.Inject;
+
+/**
+ * The root of the object graph without list
+ *
+ * @see org.apache.reef.tang.test.RootImplementation
+ */
+public class RootImplementationWithoutList implements RootInterface {
+  // TODO: Remove this class after #192 is fixed
+  private final String requiredString;
+  private final String optionalString;
+  private final UnitClass unit;
+  private final Handler<String> stringHandler;
+  private final Handler<Integer> integerHandler;
+  private final AnInterface anInterface;
+  private final int anInt;
+  private final double aDouble;
+  private final InjectableClass injectableClass;
+  private final SetOfImplementations setOfImplementations;
+  private final SetOfBaseTypes setOfBaseTypes;
+  private final CyclicDependency cyclicDependency;
+
+  @Inject
+  public RootImplementationWithoutList(
+      @Parameter(TestConfigurationWithoutList.RequiredString.class) final String requiredString,
+      @Parameter(TestConfigurationWithoutList.OptionalString.class) final String optionalString,
+      @Parameter(TestConfigurationWithoutList.StringHandler.class) final Handler<String> stringHandler,
+      @Parameter(TestConfigurationWithoutList.IntegerHandler.class) final Handler<Integer> integerHandler,
+      @Parameter(TestConfigurationWithoutList.NamedParameterInteger.class) final int anInt,
+      @Parameter(TestConfigurationWithoutList.NamedParameterDouble.class) double aDouble,
+      final UnitClass unit,
+      final AnInterface anInterface,
+      final InjectableClass injectableClass,
+      final SetOfImplementations setOfImplementations,
+      final SetOfBaseTypes setOfBaseTypes,
+      CyclicDependency cyclicDependency) {
+
+    this.requiredString = requiredString;
+    this.optionalString = optionalString;
+    this.unit = unit;
+    this.stringHandler = stringHandler;
+    this.integerHandler = integerHandler;
+    this.anInterface = anInterface;
+    this.anInt = anInt;
+    this.aDouble = aDouble;
+    this.injectableClass = injectableClass;
+    this.setOfImplementations = setOfImplementations;
+    this.setOfBaseTypes = setOfBaseTypes;
+    this.cyclicDependency = cyclicDependency;
+  }
+
+  @Override
+  public boolean isValid() {
+    if (!this.setOfImplementations.isValid()) {
+      return false;
+    }
+    if (!this.requiredString.equals(TestConfiguration.REQUIRED_STRING_VALUE)) {
+      return false;
+    }
+
+    if (!this.optionalString.equals(TestConfiguration.OPTIONAL_STRING_VALUE)) {
+      return false;
+    }
+
+    this.integerHandler.process(3);
+    this.stringHandler.process("three");
+    if (this.unit.getIntValue() != 3) {
+      return false;
+    }
+    if (!this.unit.getStringValue().equals("three")) {
+      return false;
+    }
+    if (this.anInterface == null) {
+      return false;
+    }
+
+    if (this.aDouble != TestConfiguration.NAMED_PARAMETER_DOUBLE_VALUE) {
+      return false;
+    }
+    if (this.anInt != TestConfiguration.NAMED_PARAMETER_INTEGER_VALUE) {
+      return false;
+    }
+
+    return true;
+  }
+
+
+  @Override
+  public boolean equals(Object o) {
+    if (this == o) return true;
+    if (o == null || getClass() != o.getClass()) return false;
+
+    RootImplementationWithoutList that = (RootImplementationWithoutList) o;
+
+    if (Double.compare(that.aDouble, aDouble) != 0) return false;
+    if (anInt != that.anInt) return false;
+    if (anInterface != null ? !anInterface.equals(that.anInterface) : that.anInterface != null) return false;
+    if (integerHandler != null ? !integerHandler.equals(that.integerHandler) : that.integerHandler != null)
+      return false;
+    if (optionalString != null ? !optionalString.equals(that.optionalString) : that.optionalString != null)
+      return false;
+    if (requiredString != null ? !requiredString.equals(that.requiredString) : that.requiredString != null)
+      return false;
+    if (stringHandler != null ? !stringHandler.equals(that.stringHandler) : that.stringHandler != null) return false;
+    if (unit != null ? !unit.equals(that.unit) : that.unit != null) return false;
+    if (injectableClass != null ? !injectableClass.equals(that.injectableClass) : that.injectableClass != null)
+      return false;
+    if (setOfImplementations != null ? !setOfImplementations.equals(that.setOfImplementations) : that.setOfImplementations != null)
+      return false;
+    if (setOfBaseTypes != null ? !setOfBaseTypes.equals(that.setOfBaseTypes) : that.setOfBaseTypes != null)
+      return false;
+    if (cyclicDependency != null ? !cyclicDependency.equals(that.cyclicDependency) : that.cyclicDependency != null)
+      return false;
+
+    return true;
+  }
+
+  @Override
+  public int hashCode() {
+    int result;
+    long temp;
+    result = requiredString != null ? requiredString.hashCode() : 0;
+    result = 31 * result + (optionalString != null ? optionalString.hashCode() : 0);
+    result = 31 * result + (unit != null ? unit.hashCode() : 0);
+    result = 31 * result + (stringHandler != null ? stringHandler.hashCode() : 0);
+    result = 31 * result + (integerHandler != null ? integerHandler.hashCode() : 0);
+    result = 31 * result + (anInterface != null ? anInterface.hashCode() : 0);
+    result = 31 * result + anInt;
+    temp = Double.doubleToLongBits(aDouble);
+    result = 31 * result + (int) (temp ^ (temp >>> 32));
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootInterface.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootInterface.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootInterface.java
new file mode 100644
index 0000000..210726b
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RootInterface.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test;
+
+/**
+ * The interface for the root of the test object graph instantiated.
+ */
+public interface RootInterface {
+
+  /**
+   * @return true, if the object graph has been instantiated correctly, false otherwise.
+   */
+  public boolean isValid();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RoundTripTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RoundTripTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RoundTripTest.java
new file mode 100644
index 0000000..9f012e5
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/test/RoundTripTest.java
@@ -0,0 +1,56 @@
+/**
+ * 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.test;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.implementation.protobuf.ProtocolBufferClassHierarchy;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Base class for roundtrip tests. The idea is that serializers implement roundTrip() and then get tested by the tests
+ * in this class.
+ */
+public abstract class RoundTripTest {
+
+  public abstract Configuration roundTrip(final Configuration configuration) throws Exception;
+
+  public abstract Configuration roundTrip(final Configuration configuration, final ClassHierarchy classHierarchy) throws Exception;
+
+  @Test
+  public void testRoundTrip() throws Exception {
+    // TODO: use 'getConfiguration' instead of 'getConfigurationWithoutList' after #192 is fixed
+    final Configuration conf = ObjectTreeTest.getConfigurationWithoutList();
+    final RootInterface before = Tang.Factory.getTang().newInjector(conf).getInstance(RootInterface.class);
+    final RootInterface after = Tang.Factory.getTang().newInjector(roundTrip(conf)).getInstance(RootInterface.class);
+    Assert.assertEquals("Configuration conversion to and from Avro datatypes failed.", before, after);
+  }
+
+  @Test
+  public void testRoundTripWithClassHierarchy() throws Exception {
+    // TODO: use 'getConfiguration' instead of 'getConfigurationWithoutList' after #192 is fixed
+    final Configuration confBefore = ObjectTreeTest.getConfigurationWithoutList();
+    final ClassHierarchy c = new ProtocolBufferClassHierarchy(ProtocolBufferClassHierarchy.serialize(confBefore.getClassHierarchy()));
+    final Configuration confAfter = roundTrip(confBefore, c);
+    Assert.assertEquals(confBefore.getNamedParameters().size(), confAfter.getNamedParameters().size());
+    //For now, we cannot use ProtocolBufferClassHierarchy to do injection
+  }
+}