Skip to content
Permalink
Browse files

Allow @when ate class level in modules

If a @when is defined for the whole module, all methods will inherit of the
specified condition.
Method will ne be allowed to use @when if the module define one at the class level.
  • Loading branch information
a-peyrard committed Feb 8, 2015
1 parent 05bcab4 commit f1d5b05467fb9de9584ae813d1ec0f0a76cf87ad
@@ -6,6 +6,7 @@


import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.Iterables;
import org.junit.AfterClass;
import org.junit.Before;
@@ -15,6 +16,7 @@
import java.util.Set;
import restx.factory.Factory;
import restx.factory.Name;
import restx.factory.conditional.components.TestInterfaces;
import restx.factory.conditional.components.TestModuleWithConditional;

/**
@@ -86,4 +88,25 @@ public void should_provide_component_if_condition_is_verified_and_use_name_and_p
pioneer = factory.getComponent(Name.of(TestModuleWithConditional.Pioneer.class, "physics"));
assertThat(pioneer.name()).isEqualTo("Pierre Currie");
}

@Test
public void should_use_modules_condition_on_all_its_components() {
Factory factory = Factory.newInstance();
TestInterfaces.Resolver resolver = factory.getComponent(TestInterfaces.Resolver.class);
assertThat(resolver.resolve("foo")).isEqualTo("prod:foo");
Optional<TestInterfaces.Workspace> workspace = factory.queryByClass(TestInterfaces.Workspace.class).findOneAsComponent();
assertThat(workspace.isPresent()).isFalse();
String dbType = factory.getComponent(Name.of(String.class, "db.type"));
assertThat(dbType).isEqualTo("postgres");

overrideComponents().set("my-mode", "dev");

factory = Factory.newInstance();
resolver = factory.getComponent(TestInterfaces.Resolver.class);
assertThat(resolver.resolve("foo")).isEqualTo("dev:foo");
workspace = factory.queryByClass(TestInterfaces.Workspace.class).findOneAsComponent();
assertThat(workspace.isPresent()).isTrue();
dbType = factory.getComponent(Name.of(String.class, "db.type"));
assertThat(dbType).isEqualTo("derby");
}
}
@@ -0,0 +1,27 @@
package restx.factory.conditional.components;

import javax.inject.Named;
import restx.factory.Module;
import restx.factory.Provides;

/**
* @author apeyrard
*/
@Module
public class TestClassicModule {

@Provides
public TestInterfaces.Resolver prodResolver() {
return new TestInterfaces.Resolver() {
@Override
public String resolve(String constraint) {
return "prod:"+constraint;
}
};
}

@Provides @Named("db.type")
public String dbType() {
return "postgres";
}
}
@@ -0,0 +1,43 @@
package restx.factory.conditional.components;

import com.google.common.collect.ImmutableList;

import java.util.List;
import javax.inject.Named;
import restx.factory.Alternative;
import restx.factory.Module;
import restx.factory.Provides;
import restx.factory.When;

/**
* @author apeyrard
*/
@Module(priority = -100)
@When(name = "my-mode", value = "dev")
public class TestDevModule {

@Alternative(to = TestInterfaces.Resolver.class, named = "prodResolver")
public TestInterfaces.Resolver devResolver() {
return new TestInterfaces.Resolver() {
@Override
public String resolve(String constraint) {
return "dev:"+constraint;
}
};
}

@Provides
public TestInterfaces.Workspace workspace() {
return new TestInterfaces.Workspace() {
@Override
public List<String> modules() {
return ImmutableList.of("mod1", "mod2");
}
};
}

@Provides @Named("db.type")
public String dbType() {
return "derby";
}
}
@@ -0,0 +1,17 @@
package restx.factory.conditional.components;

import java.util.List;

/**
* @author apeyrard
*/
public class TestInterfaces {

public static interface Resolver {
String resolve(String constraint);
}

public static interface Workspace {
List<String> modules();
}
}
@@ -81,6 +81,7 @@ private void processModules(RoundEnvironment roundEnv) throws IOException {
}
TypeElement typeElem = (TypeElement) annotation;
Module mod = typeElem.getAnnotation(Module.class);
When classWhen = typeElem.getAnnotation(When.class);

ModuleClass module = new ModuleClass(typeElem.getQualifiedName().toString(), typeElem, mod.priority());
for (Element element : typeElem.getEnclosedElements()) {
@@ -93,64 +94,79 @@ private void processModules(RoundEnvironment roundEnv) throws IOException {
&& element.getKind() == ElementKind.METHOD) {

ExecutableElement exec = (ExecutableElement) element;
When when = exec.getAnnotation(When.class);
When methodWhen = exec.getAnnotation(When.class);

// multiple cases, provides only, provides with when, and alternative

if (provides != null && when == null) {
if (provides != null && methodWhen == null && classWhen == null) {
// add a provider method to the module
processProviderMethod(mod, module, provides, exec);
} else if (provides != null) {
// we need to create a conditional provider method
processConditionalProviderMethod(
mod,
module,
exec.getReturnType().toString(),
getInjectionName(exec.getAnnotation(Named.class)).or(exec.getSimpleName().toString()),
provides.priority() == 0 ? mod.priority() : provides.priority(),
when,
"Conditional",
exec
);
} else if (alternative != null) {
// when annotation is required with alternative
if (when == null) {
error("an Alternative MUST be annotated with @When to tell when it must be activated", exec);
continue;
}

TypeElement alternativeTo = null;
try {
alternative.to();
} catch (MirroredTypeException mte) {
alternativeTo = asTypeElement(mte.getTypeMirror());
}

String namedAttribute = alternative.named();
Optional<String> injectionName = getInjectionName(alternativeTo.getAnnotation(Named.class));
String componentName;
if (!namedAttribute.isEmpty()) {
// the conditional component name is the one specified in @Alternative annotation
componentName = namedAttribute;
} else if (injectionName.isPresent()) {
// or the Name of the reference class
componentName = injectionName.get();
} else {

// When can be either defined at class level, or on the method. But both are not allowed.
When whenToUse;
if (classWhen != null) {
if (methodWhen != null) {
error("the module class is annotated with @When, so methods are not allowed to be annotated with @When", exec);
continue;
}
whenToUse = classWhen;
} else {
// or the simple name of the produced class
componentName = alternativeTo.getSimpleName().toString();
whenToUse = methodWhen;
}

// add a conditional provider method to the module
processConditionalProviderMethod(
mod,
module,
alternativeTo.getQualifiedName().toString(),
componentName,
alternative.priority(),
when,
"Alternative",
exec
);
if (provides != null) {
// we need to create a conditional provider method
processConditionalProviderMethod(
mod,
module,
exec.getReturnType().toString(),
getInjectionName(exec.getAnnotation(Named.class)).or(exec.getSimpleName().toString()),
provides.priority() == 0 ? mod.priority() : provides.priority(),
whenToUse,
"Conditional",
exec
);
} else if (alternative != null) {
// when annotation is required with alternative
if (whenToUse == null) {
error("an Alternative MUST be annotated with @When to tell when it must be activated, or the whole module must be annotated with @When", exec);
continue;
}

TypeElement alternativeTo = null;
try {
alternative.to();
} catch (MirroredTypeException mte) {
alternativeTo = asTypeElement(mte.getTypeMirror());
}

String namedAttribute = alternative.named();
Optional<String> injectionName = getInjectionName(alternativeTo.getAnnotation(Named.class));
String componentName;
if (!namedAttribute.isEmpty()) {
// the conditional component name is the one specified in @Alternative annotation
componentName = namedAttribute;
} else if (injectionName.isPresent()) {
// or the Name of the reference class
componentName = injectionName.get();
} else {
// or the simple name of the produced class
componentName = alternativeTo.getSimpleName().toString();
}

// add a conditional provider method to the module
processConditionalProviderMethod(
mod,
module,
alternativeTo.getQualifiedName().toString(),
componentName,
alternative.priority(),
whenToUse,
"Alternative",
exec
);
}
}
}
}

0 comments on commit f1d5b05

Please sign in to comment.
You can’t perform that action at this time.