Skip to content

Commit f1d5b05

Browse files
committed
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.
1 parent 05bcab4 commit f1d5b05

5 files changed

Lines changed: 176 additions & 50 deletions

File tree

restx-factory-testing/src/test/java/restx/factory/conditional/ConditionalTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77

88
import com.google.common.base.Function;
9+
import com.google.common.base.Optional;
910
import com.google.common.collect.Iterables;
1011
import org.junit.AfterClass;
1112
import org.junit.Before;
@@ -15,6 +16,7 @@
1516
import java.util.Set;
1617
import restx.factory.Factory;
1718
import restx.factory.Name;
19+
import restx.factory.conditional.components.TestInterfaces;
1820
import restx.factory.conditional.components.TestModuleWithConditional;
1921

2022
/**
@@ -86,4 +88,25 @@ public void should_provide_component_if_condition_is_verified_and_use_name_and_p
8688
pioneer = factory.getComponent(Name.of(TestModuleWithConditional.Pioneer.class, "physics"));
8789
assertThat(pioneer.name()).isEqualTo("Pierre Currie");
8890
}
91+
92+
@Test
93+
public void should_use_modules_condition_on_all_its_components() {
94+
Factory factory = Factory.newInstance();
95+
TestInterfaces.Resolver resolver = factory.getComponent(TestInterfaces.Resolver.class);
96+
assertThat(resolver.resolve("foo")).isEqualTo("prod:foo");
97+
Optional<TestInterfaces.Workspace> workspace = factory.queryByClass(TestInterfaces.Workspace.class).findOneAsComponent();
98+
assertThat(workspace.isPresent()).isFalse();
99+
String dbType = factory.getComponent(Name.of(String.class, "db.type"));
100+
assertThat(dbType).isEqualTo("postgres");
101+
102+
overrideComponents().set("my-mode", "dev");
103+
104+
factory = Factory.newInstance();
105+
resolver = factory.getComponent(TestInterfaces.Resolver.class);
106+
assertThat(resolver.resolve("foo")).isEqualTo("dev:foo");
107+
workspace = factory.queryByClass(TestInterfaces.Workspace.class).findOneAsComponent();
108+
assertThat(workspace.isPresent()).isTrue();
109+
dbType = factory.getComponent(Name.of(String.class, "db.type"));
110+
assertThat(dbType).isEqualTo("derby");
111+
}
89112
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package restx.factory.conditional.components;
2+
3+
import javax.inject.Named;
4+
import restx.factory.Module;
5+
import restx.factory.Provides;
6+
7+
/**
8+
* @author apeyrard
9+
*/
10+
@Module
11+
public class TestClassicModule {
12+
13+
@Provides
14+
public TestInterfaces.Resolver prodResolver() {
15+
return new TestInterfaces.Resolver() {
16+
@Override
17+
public String resolve(String constraint) {
18+
return "prod:"+constraint;
19+
}
20+
};
21+
}
22+
23+
@Provides @Named("db.type")
24+
public String dbType() {
25+
return "postgres";
26+
}
27+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package restx.factory.conditional.components;
2+
3+
import com.google.common.collect.ImmutableList;
4+
5+
import java.util.List;
6+
import javax.inject.Named;
7+
import restx.factory.Alternative;
8+
import restx.factory.Module;
9+
import restx.factory.Provides;
10+
import restx.factory.When;
11+
12+
/**
13+
* @author apeyrard
14+
*/
15+
@Module(priority = -100)
16+
@When(name = "my-mode", value = "dev")
17+
public class TestDevModule {
18+
19+
@Alternative(to = TestInterfaces.Resolver.class, named = "prodResolver")
20+
public TestInterfaces.Resolver devResolver() {
21+
return new TestInterfaces.Resolver() {
22+
@Override
23+
public String resolve(String constraint) {
24+
return "dev:"+constraint;
25+
}
26+
};
27+
}
28+
29+
@Provides
30+
public TestInterfaces.Workspace workspace() {
31+
return new TestInterfaces.Workspace() {
32+
@Override
33+
public List<String> modules() {
34+
return ImmutableList.of("mod1", "mod2");
35+
}
36+
};
37+
}
38+
39+
@Provides @Named("db.type")
40+
public String dbType() {
41+
return "derby";
42+
}
43+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package restx.factory.conditional.components;
2+
3+
import java.util.List;
4+
5+
/**
6+
* @author apeyrard
7+
*/
8+
public class TestInterfaces {
9+
10+
public static interface Resolver {
11+
String resolve(String constraint);
12+
}
13+
14+
public static interface Workspace {
15+
List<String> modules();
16+
}
17+
}

restx-factory/src/main/java/restx/factory/processor/FactoryAnnotationProcessor.java

Lines changed: 66 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ private void processModules(RoundEnvironment roundEnv) throws IOException {
8181
}
8282
TypeElement typeElem = (TypeElement) annotation;
8383
Module mod = typeElem.getAnnotation(Module.class);
84+
When classWhen = typeElem.getAnnotation(When.class);
8485

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

9596
ExecutableElement exec = (ExecutableElement) element;
96-
When when = exec.getAnnotation(When.class);
97+
When methodWhen = exec.getAnnotation(When.class);
9798

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

100-
if (provides != null && when == null) {
101+
if (provides != null && methodWhen == null && classWhen == null) {
101102
// add a provider method to the module
102103
processProviderMethod(mod, module, provides, exec);
103-
} else if (provides != null) {
104-
// we need to create a conditional provider method
105-
processConditionalProviderMethod(
106-
mod,
107-
module,
108-
exec.getReturnType().toString(),
109-
getInjectionName(exec.getAnnotation(Named.class)).or(exec.getSimpleName().toString()),
110-
provides.priority() == 0 ? mod.priority() : provides.priority(),
111-
when,
112-
"Conditional",
113-
exec
114-
);
115-
} else if (alternative != null) {
116-
// when annotation is required with alternative
117-
if (when == null) {
118-
error("an Alternative MUST be annotated with @When to tell when it must be activated", exec);
119-
continue;
120-
}
121-
122-
TypeElement alternativeTo = null;
123-
try {
124-
alternative.to();
125-
} catch (MirroredTypeException mte) {
126-
alternativeTo = asTypeElement(mte.getTypeMirror());
127-
}
128-
129-
String namedAttribute = alternative.named();
130-
Optional<String> injectionName = getInjectionName(alternativeTo.getAnnotation(Named.class));
131-
String componentName;
132-
if (!namedAttribute.isEmpty()) {
133-
// the conditional component name is the one specified in @Alternative annotation
134-
componentName = namedAttribute;
135-
} else if (injectionName.isPresent()) {
136-
// or the Name of the reference class
137-
componentName = injectionName.get();
104+
} else {
105+
106+
// When can be either defined at class level, or on the method. But both are not allowed.
107+
When whenToUse;
108+
if (classWhen != null) {
109+
if (methodWhen != null) {
110+
error("the module class is annotated with @When, so methods are not allowed to be annotated with @When", exec);
111+
continue;
112+
}
113+
whenToUse = classWhen;
138114
} else {
139-
// or the simple name of the produced class
140-
componentName = alternativeTo.getSimpleName().toString();
115+
whenToUse = methodWhen;
141116
}
142117

143-
// add a conditional provider method to the module
144-
processConditionalProviderMethod(
145-
mod,
146-
module,
147-
alternativeTo.getQualifiedName().toString(),
148-
componentName,
149-
alternative.priority(),
150-
when,
151-
"Alternative",
152-
exec
153-
);
118+
if (provides != null) {
119+
// we need to create a conditional provider method
120+
processConditionalProviderMethod(
121+
mod,
122+
module,
123+
exec.getReturnType().toString(),
124+
getInjectionName(exec.getAnnotation(Named.class)).or(exec.getSimpleName().toString()),
125+
provides.priority() == 0 ? mod.priority() : provides.priority(),
126+
whenToUse,
127+
"Conditional",
128+
exec
129+
);
130+
} else if (alternative != null) {
131+
// when annotation is required with alternative
132+
if (whenToUse == null) {
133+
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);
134+
continue;
135+
}
136+
137+
TypeElement alternativeTo = null;
138+
try {
139+
alternative.to();
140+
} catch (MirroredTypeException mte) {
141+
alternativeTo = asTypeElement(mte.getTypeMirror());
142+
}
143+
144+
String namedAttribute = alternative.named();
145+
Optional<String> injectionName = getInjectionName(alternativeTo.getAnnotation(Named.class));
146+
String componentName;
147+
if (!namedAttribute.isEmpty()) {
148+
// the conditional component name is the one specified in @Alternative annotation
149+
componentName = namedAttribute;
150+
} else if (injectionName.isPresent()) {
151+
// or the Name of the reference class
152+
componentName = injectionName.get();
153+
} else {
154+
// or the simple name of the produced class
155+
componentName = alternativeTo.getSimpleName().toString();
156+
}
157+
158+
// add a conditional provider method to the module
159+
processConditionalProviderMethod(
160+
mod,
161+
module,
162+
alternativeTo.getQualifiedName().toString(),
163+
componentName,
164+
alternative.priority(),
165+
whenToUse,
166+
"Alternative",
167+
exec
168+
);
169+
}
154170
}
155171
}
156172
}

0 commit comments

Comments
 (0)