001 package org.picocontainer.containers;
002
003 import org.junit.Test;
004 import static org.junit.Assert.fail;
005 import static org.junit.Assert.assertNotNull;
006 import static org.junit.Assert.assertTrue;
007 import org.picocontainer.MutablePicoContainer;
008 import org.picocontainer.DefaultPicoContainer;
009 import static org.picocontainer.BindKey.bindKey;
010 import org.picocontainer.annotations.Bind;
011 import org.picocontainer.injectors.AbstractInjector;
012
013 import java.lang.annotation.Retention;
014 import java.lang.annotation.RetentionPolicy;
015 import java.lang.annotation.Target;
016 import java.lang.annotation.ElementType;
017
018 public class TieringPicoContainerTestCase {
019
020 public static class Couch {
021 }
022
023 public static class TiredPerson {
024 private Couch couchToSitOn;
025
026 public TiredPerson(Couch couchToSitOn) {
027 this.couchToSitOn = couchToSitOn;
028 }
029 }
030
031 @Test
032 public void testThatGrandparentTraversalForComponentsCanBeBlocked() {
033 MutablePicoContainer grandparent = new TieringPicoContainer();
034 MutablePicoContainer parent = grandparent.makeChildContainer();
035 MutablePicoContainer child = parent.makeChildContainer();
036 grandparent.addComponent(Couch.class);
037 child.addComponent(TiredPerson.class);
038
039 TiredPerson tp = null;
040 try {
041 tp = child.getComponent(TiredPerson.class);
042 fail("should have barfed");
043 } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
044 // expected
045 }
046
047 }
048
049 @Test
050 public void testThatParentTraversalIsOkForTiering() {
051 MutablePicoContainer parent = new TieringPicoContainer();
052 MutablePicoContainer child = parent.makeChildContainer();
053 parent.addComponent(Couch.class);
054 child.addComponent(TiredPerson.class);
055
056 TiredPerson tp = child.getComponent(TiredPerson.class);
057 assertNotNull(tp);
058 assertNotNull(tp.couchToSitOn);
059
060 }
061
062 public static class Doctor {
063 private TiredPerson tiredPerson;
064
065 public Doctor(TiredPerson tiredPerson) {
066 this.tiredPerson = tiredPerson;
067 }
068 }
069
070 public static class TiredDoctor {
071 private Couch couchToSitOn;
072 private final TiredPerson tiredPerson;
073
074 public TiredDoctor(Couch couchToSitOn, TiredPerson tiredPerson) {
075 this.couchToSitOn = couchToSitOn;
076 this.tiredPerson = tiredPerson;
077 }
078 }
079
080 @Test
081 public void testThatParentTraversalIsOnlyBlockedOneTierAtATime() {
082 MutablePicoContainer gp = new TieringPicoContainer();
083 MutablePicoContainer p = gp.makeChildContainer();
084 MutablePicoContainer c = p.makeChildContainer();
085 gp.addComponent(Couch.class);
086 p.addComponent(TiredPerson.class);
087 c.addComponent(Doctor.class);
088 c.addComponent(TiredDoctor.class);
089 Doctor d = c.getComponent(Doctor.class);
090 assertNotNull(d);
091 assertNotNull(d.tiredPerson);
092 assertNotNull(d.tiredPerson.couchToSitOn);
093 try {
094 TiredDoctor td = c.getComponent(TiredDoctor.class);
095 fail("should have barfed");
096 } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
097 // expected
098 }
099
100 }
101
102 @Retention(RetentionPolicy.RUNTIME)
103 @Target({ElementType.FIELD, ElementType.PARAMETER})
104 @Bind
105 public static @interface Grouchy {}
106
107 public static class GrouchyTiredPerson extends TiredPerson {
108 public GrouchyTiredPerson(Couch couchToSitOn) {
109 super(couchToSitOn);
110 }
111 }
112
113 @Retention(RetentionPolicy.RUNTIME)
114 @Target({ElementType.FIELD, ElementType.PARAMETER})
115 @Bind
116 public static @interface Polite {}
117
118 public static class PoliteTiredPerson extends TiredPerson {
119 public PoliteTiredPerson(Couch couchToSitOn) {
120 super(couchToSitOn);
121 }
122 }
123
124 public static class DiscerningDoctor {
125 private final TiredPerson tiredPerson;
126
127 public DiscerningDoctor(@Polite TiredPerson tiredPerson) {
128 this.tiredPerson = tiredPerson;
129 }
130 }
131
132 @Test
133 public void testThatGrandparentTraversalForComponentsCanBeBlockedEvenForAnnotatedInjections() {
134 MutablePicoContainer grandparent = new TieringPicoContainer();
135 MutablePicoContainer parent = grandparent.makeChildContainer();
136 MutablePicoContainer child = parent.makeChildContainer();
137 grandparent.addComponent(Couch.class);
138 grandparent.addComponent(bindKey(TiredPerson.class, Polite.class), PoliteTiredPerson.class);
139 grandparent.addComponent(bindKey(TiredPerson.class, Grouchy.class), GrouchyTiredPerson.class);
140 child.addComponent(DiscerningDoctor.class);
141
142 assertNotNull(grandparent.getComponent(TiredPerson.class, Polite.class));
143 assertNotNull(grandparent.getComponent(TiredPerson.class, Grouchy.class));
144
145 DiscerningDoctor dd = null;
146 try {
147 dd = child.getComponent(DiscerningDoctor.class);
148 fail("should have barfed");
149 } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
150 // expected
151 }
152
153 }
154
155 @Test
156 public void testThatGrandparentTraversalForComponentsCanBeBlockedEvenForAnnotatedInjections2() {
157 MutablePicoContainer grandparent = new TieringPicoContainer();
158 grandparent.addComponent(Couch.class);
159 grandparent.addComponent(bindKey(TiredPerson.class, Polite.class), PoliteTiredPerson.class);
160 grandparent.addComponent(bindKey(TiredPerson.class, Grouchy.class), GrouchyTiredPerson.class);
161 grandparent.addComponent(DiscerningDoctor.class);
162
163 assertNotNull(grandparent.getComponent(TiredPerson.class, Polite.class));
164 assertNotNull(grandparent.getComponent(TiredPerson.class, Grouchy.class));
165
166 DiscerningDoctor dd = grandparent.getComponent(DiscerningDoctor.class);
167 assertNotNull(dd.tiredPerson);
168 assertTrue(dd.tiredPerson instanceof PoliteTiredPerson);
169
170 }
171
172
173
174
175 }