Skip to content

Commit

Permalink
New DependencyProvider decorator to provide empty objects for designa…
Browse files Browse the repository at this point in the history
…ted classes
  • Loading branch information
rafaeldff committed Apr 30, 2012
1 parent add94c5 commit d293eae
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 1 deletion.
42 changes: 42 additions & 0 deletions src/br/com/caelum/iogi/EmptyObjectsProvider.java
@@ -0,0 +1,42 @@
package br.com.caelum.iogi;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import br.com.caelum.iogi.reflection.Target;
import br.com.caelum.iogi.spi.DependencyProvider;

import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;

public class EmptyObjectsProvider implements DependencyProvider {
public static final Map<? extends Class<?>, ? extends Supplier<?>> JAVA_EMPTY_SUPPLIERS = ImmutableMap.of(List.class,
new Supplier<List<Object>>() {
public List<Object> get() {
return new ArrayList<Object>();
};
});
private final Map<? extends Class<?>, ? extends Supplier<?>> emptyInstances;
private final DependencyProvider underlying;

public EmptyObjectsProvider(DependencyProvider underlying, Map<? extends Class<?>, ? extends Supplier<?>> emptyInstances) {
this.underlying = underlying;
this.emptyInstances = emptyInstances;
}

@Override
public boolean canProvide(Target<?> target) {
return selfCanProvide(target) || underlying.canProvide(target);
}

private boolean selfCanProvide(Target<?> target) {
return emptyInstances.containsKey(target.getClassType());
}

@Override
public Object provide(Target<?> target) {
return underlying.canProvide(target) ? underlying.provide(target) : emptyInstances.get(target.getClassType()).get();
}

}
2 changes: 1 addition & 1 deletion src/br/com/caelum/iogi/Iogi.java
Expand Up @@ -67,7 +67,7 @@ public Iogi(final DependencyProvider dependencyProvider, final LocaleProvider lo
.add(fallbackTo(new ShortPrimitiveConverter(), (short)0))
.add(new ArrayInstantiator(new DelegateToAllInstantatiors()))
.add(new ListInstantiator(new DelegateToAllInstantatiors()))
.add(new ObjectInstantiator(new DelegateToAllInstantatiors(), dependencyProvider, new ParanamerParameterNamesProvider()))
.add(new ObjectInstantiator(new DelegateToAllInstantatiors(), new EmptyObjectsProvider(dependencyProvider, EmptyObjectsProvider.JAVA_EMPTY_SUPPLIERS), new ParanamerParameterNamesProvider()))
.build();

this.allInstantiators = new MultiInstantiator(all);
Expand Down
152 changes: 152 additions & 0 deletions test/br/com/caelum/iogi/EmptyObjectsProviderTest.java
@@ -0,0 +1,152 @@
package br.com.caelum.iogi;

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;

import br.com.caelum.iogi.conversion.StringConverter;
import br.com.caelum.iogi.parameters.Parameter;
import br.com.caelum.iogi.parameters.Parameters;
import br.com.caelum.iogi.reflection.ParanamerParameterNamesProvider;
import br.com.caelum.iogi.reflection.Target;
import br.com.caelum.iogi.spi.DependencyProvider;

import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import static org.hamcrest.Matchers.instanceOf;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

public class EmptyObjectsProviderTest {
private Mockery context = new Mockery();
private DependencyProvider underlying = context.mock(DependencyProvider.class);

private Class<?> classThatMayBeEmpty = MayBeEmpty.class;
private Supplier<MayBeEmpty> emptyValueSupplier = new Supplier<MayBeEmpty>() {
@Override
public MayBeEmpty get() {
return new MayBeEmpty();
}
};
private Target<?> targetForEmptyObject = Target.create(classThatMayBeEmpty, "");
private EmptyObjectsProvider provider =
new EmptyObjectsProvider(underlying, ImmutableMap.of(classThatMayBeEmpty, emptyValueSupplier));

public void assumeUnderlyingCannotProvideAnything() {
context.checking(new Expectations() {{
allowing(underlying).canProvide(with(any(Target.class))); will(returnValue(false));
}});
}

@After
public void tearDown() {
context.assertIsSatisfied();
}

@Test
public void willProvideAnEmptyObjectWhenOneIsRequired() throws Exception {
assumeUnderlyingCannotProvideAnything();
assertTrue(provider.canProvide(targetForEmptyObject));
Assert.assertThat(provider.provide(targetForEmptyObject), instanceOf(MayBeEmpty.class));
}

@Test
public void willNotProvideObjectsThatHaveNoMappingNorAreProvidableByTheUnderlyingProvider() throws Exception {
assumeUnderlyingCannotProvideAnything();
final Target<NormalObject> target = Target.create(NormalObject.class, "");
assertFalse(provider.canProvide(target));
}

@Test
public void objectsProvidedForAGivenTargetWillNotBeTheSame() throws Exception {
assumeUnderlyingCannotProvideAnything();
assertTrue(provider.canProvide(targetForEmptyObject));
Object first = provider.provide(targetForEmptyObject);
Object second = provider.provide(targetForEmptyObject);

Assert.assertNotSame(first, second);
}

@Test
public void willDelegateWhenTheUnderlyingProviderIsAbleToProvideForTheTarget() throws Exception {
final Target<?> target = Target.create(DifferentObject.class, "");
final Object provided = new DifferentObject();
context.checking(new Expectations() {{
oneOf(underlying).canProvide(target); will(returnValue(true));
oneOf(underlying).provide(target); will(returnValue(provided));
}});

Assert.assertSame(provided, provider.provide(target));
}

@Test
public void ifUnderlyingIsAbleThenWillDelegateEvenIfCanProvideEmptyInstance() throws Exception {
final Target<?> target = Target.create(MayBeEmpty.class, "");
final Object provided = new MayBeEmpty();
context.checking(new Expectations() {{
oneOf(underlying).canProvide(target); will(returnValue(true));
oneOf(underlying).provide(target); will(returnValue(provided));
}});

Assert.assertSame(provided, provider.provide(target));
}

private Instantiator<Object> instantiator = new MultiInstantiator(
ImmutableList.of(
new StringConverter(),
new ObjectInstantiator(new RecursiveInstantiator(), provider, new ParanamerParameterNamesProvider())));
private final class RecursiveInstantiator implements Instantiator<Object> {
@Override
public boolean isAbleToInstantiate(Target<?> target) {
return instantiator.isAbleToInstantiate(target);
}

@Override
public Object instantiate(Target<?> target, Parameters parameters) {
return instantiator.instantiate(target, parameters);
}
}

@Test
public void canBeUsedToInstantiateAnObject() throws Exception {
assumeUnderlyingCannotProvideAnything();
Target<DependsOnEmptyAndNormal> target = Target.create(DependsOnEmptyAndNormal.class, "root");
Parameters parameters = new Parameters(new Parameter("root.normal.parameter", "foo"));
DependsOnEmptyAndNormal object = (DependsOnEmptyAndNormal) instantiator.instantiate(target, parameters);
assertEquals("foo", object.normal.parameter);
assertThat(object.mayBeEmpty, instanceOf(MayBeEmpty.class));
}

static class NormalObject {
private final String parameter;

public NormalObject(String parameter) {
this.parameter = parameter;
}
}

static class MayBeEmpty {
}

static class DependsOnEmptyAndNormal {
final NormalObject normal;
final MayBeEmpty mayBeEmpty;

public DependsOnEmptyAndNormal(MayBeEmpty mayBeEmpty, NormalObject normal) {
this.mayBeEmpty = mayBeEmpty;
this.normal = normal;
}
}

static class DifferentObject {

}

}
13 changes: 13 additions & 0 deletions test/br/com/caelum/iogi/ObjectInstantiationTests.java
Expand Up @@ -270,6 +270,19 @@ public void willReturnNullIfThereAreNoParametersNorDependenciesAtLeastForOneForm
assertNull(object);
}

@Test
public void canInstantiateObjectDependingOnAnEmptyList() throws Exception {
Target<MixedObjectAndList> target = Target.create(MixedObjectAndList.class, "root");

MixedObjectAndList object = iogi.instantiate(target, new Parameter("root.object.someString", "foo"));

OneString objectDependency = object.getObject();
List<OneString> list = object.getList();

assertEquals("foo", objectDependency.getSomeString());
assertTrue(list.isEmpty());
}

public static class HasDependency {
private final String instantiable;
private final String uninstantiable;
Expand Down

0 comments on commit d293eae

Please sign in to comment.