001 /*****************************************************************************
002 * Copyright (c) PicoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * *
008 *****************************************************************************/
009
010 package org.picocontainer.behaviors;
011
012
013 import static org.junit.Assert.assertEquals;
014 import static org.junit.Assert.assertNotNull;
015
016 import org.junit.Test;
017 import org.picocontainer.Characteristics;
018 import org.picocontainer.ComponentAdapter;
019 import org.picocontainer.ComponentFactory;
020 import org.picocontainer.DefaultPicoContainer;
021 import org.picocontainer.adapters.InstanceAdapter;
022 import org.picocontainer.injectors.AdaptingInjection;
023 import org.picocontainer.injectors.ConstructorInjection;
024 import org.picocontainer.injectors.ConstructorInjector;
025 import org.picocontainer.lifecycle.NullLifecycleStrategy;
026 import org.picocontainer.monitors.NullComponentMonitor;
027 import org.picocontainer.tck.AbstractComponentFactoryTest;
028
029
030 public class ImplementationHidingTestCase extends AbstractComponentFactoryTest{
031
032 @Test public void testAddComponentUsesImplementationHidingBehavior() {
033 DefaultPicoContainer pico =
034 new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
035 pico.addComponent("foo", String.class);
036 ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
037 assertEquals(HiddenImplementation.class, foo.getClass());
038 assertEquals(ConstructorInjector.class, ((AbstractBehavior) foo).getDelegate().getClass());
039 }
040
041 @Test public void testAddComponentUsesImplementationHidingBehaviorWithRedundantHideImplProperty() {
042 DefaultPicoContainer pico =
043 new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
044 pico.change(Characteristics.HIDE_IMPL).addComponent("foo", String.class);
045 ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
046 assertEquals(HiddenImplementation.class, foo.getClass());
047 assertEquals(ConstructorInjector.class, ((AbstractBehavior) foo).getDelegate().getClass());
048 }
049
050 @Test public void testAddComponentNoesNotUseImplementationHidingBehaviorWhenNoCachePropertyIsSpecified() {
051 DefaultPicoContainer pico =
052 new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
053 pico.change(Characteristics.NO_HIDE_IMPL).addComponent("foo", String.class);
054 ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
055 assertEquals(ConstructorInjector.class, foo.getClass());
056 }
057
058 @Test public void testAddAdapterUsesImplementationHidingBehavior() {
059 DefaultPicoContainer pico =
060 new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
061 pico.addAdapter(new InstanceAdapter("foo", "bar", new NullLifecycleStrategy(), new NullComponentMonitor()));
062 ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
063 assertEquals(HiddenImplementation.class, foo.getClass());
064 assertEquals(InstanceAdapter.class, ((AbstractBehavior) foo).getDelegate().getClass());
065 }
066
067 @Test public void testAddAdapterUsesImplementationHidingBehaviorWithRedundantHideImplProperty() {
068 DefaultPicoContainer pico =
069 new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
070 pico.change(Characteristics.HIDE_IMPL).addAdapter(new InstanceAdapter("foo", "bar", new NullLifecycleStrategy(), new NullComponentMonitor()));
071 ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
072 assertEquals(HiddenImplementation.class, foo.getClass());
073 assertEquals(InstanceAdapter.class, ((AbstractBehavior) foo).getDelegate().getClass());
074 }
075
076 @Test public void testAddAdapterNoesNotUseImplementationHidingBehaviorWhenNoCachePropertyIsSpecified() {
077 DefaultPicoContainer pico =
078 new DefaultPicoContainer(new ImplementationHiding().wrap(new ConstructorInjection()));
079 pico.change(Characteristics.NO_HIDE_IMPL).addAdapter(new InstanceAdapter("foo", "bar", new NullLifecycleStrategy(), new NullComponentMonitor()));
080 ComponentAdapter<?> foo = pico.getComponentAdapter("foo");
081 assertEquals(InstanceAdapter.class, foo.getClass());
082 }
083
084
085 private final ComponentFactory implementationHidingComponentFactory =
086 new ImplementationHiding().wrap(new AdaptingInjection());
087
088 protected ComponentFactory createComponentFactory() {
089 return implementationHidingComponentFactory;
090 }
091
092
093 public static interface NeedsStringBuilder {
094 void foo();
095 }
096 public static class NeedsStringBuilderImpl implements NeedsStringBuilder {
097 StringBuilder sb;
098
099 public NeedsStringBuilderImpl(StringBuilder sb) {
100 this.sb = sb;
101 sb.append("<init>");
102 }
103 public void foo() {
104 sb.append("foo()");
105 }
106 }
107 public static class NeedsNeedsStringBuilder {
108
109 NeedsStringBuilder nsb;
110
111 public NeedsNeedsStringBuilder(NeedsStringBuilder nsb) {
112 this.nsb = nsb;
113 }
114 public void foo() {
115 nsb.foo();
116 }
117 }
118
119 @Test public void testLazyInstantiationSideEffectWhenForceOfDelayedInstantiationOfDependantClass() {
120 DefaultPicoContainer pico =
121 new DefaultPicoContainer(new ImplementationHiding().wrap(new Caching().wrap(new ConstructorInjection())));
122 pico.addComponent(StringBuilder.class);
123 pico.addComponent(NeedsStringBuilder.class, NeedsStringBuilderImpl.class);
124 pico.addComponent(NeedsNeedsStringBuilder.class);
125 NeedsNeedsStringBuilder nnsb = pico.getComponent(NeedsNeedsStringBuilder.class);
126 assertNotNull(nnsb);
127 StringBuilder sb = pico.getComponent(StringBuilder.class);
128 assertEquals("", sb.toString()); // not instantiated yet
129 nnsb.foo();
130 assertEquals("<init>foo()", sb.toString()); // instantiated
131 }
132
133 //@Test public void shouldNotInstantiateForEveryMethodCall() {
134 // ...
135 //}
136
137 @Test public void shouldInstantiateForEveryMethodCall() {
138 cachingTestBody("<init>foo()<init>foo()", new ImplementationHiding());
139 }
140
141 @Test public void shouldNotInstantiateForEveryMethodCallIfCaching() {
142 cachingTestBody("<init>foo()foo()", new ImplementationHiding().wrap(new Caching()));
143 }
144
145 @Test public void shouldInstantiateForEveryMethodCallIfCachingWrapsImplementationHidingWhichIsFutile() {
146 cachingTestBody("<init>foo()<init>foo()", new Caching().wrap(new ImplementationHiding()));
147 }
148
149 private void cachingTestBody(String expectation, ComponentFactory compFactory) {
150 DefaultPicoContainer parent = new DefaultPicoContainer(new Caching());
151 parent.addComponent(StringBuilder.class);
152 DefaultPicoContainer pico =
153 new DefaultPicoContainer(compFactory, parent);
154 pico.addComponent(NeedsStringBuilder.class, NeedsStringBuilderImpl.class);
155 NeedsStringBuilder nsb = pico.getComponent(NeedsStringBuilder.class);
156 assertNotNull(nsb);
157 nsb.foo();
158 nsb.foo();
159 StringBuilder sb = pico.getComponent(StringBuilder.class);
160 assertEquals(expectation, sb.toString());
161 }
162
163 }