77import com .samskivert .mustache .Template ;
88import restx .common .processor .RestxAbstractProcessor ;
99import restx .factory .*;
10- import restx .factory .Name ;
1110
1211import javax .annotation .processing .RoundEnvironment ;
1312import javax .annotation .processing .SupportedAnnotationTypes ;
@@ -85,24 +84,61 @@ private void processModules(RoundEnvironment roundEnv) throws IOException {
8584
8685 ModuleClass module = new ModuleClass (typeElem .getQualifiedName ().toString (), typeElem , mod .priority ());
8786 for (Element element : typeElem .getEnclosedElements ()) {
87+ // look for Provides or Alternative elements
8888 Provides provides = element .getAnnotation (Provides .class );
89+ Alternative alternative = element .getAnnotation (Alternative .class );
8990 if (element instanceof ExecutableElement
90- && element .getKind () == ElementKind .METHOD
91- && provides != null ) {
92- ExecutableElement exec = (ExecutableElement ) element ;
93-
94- ProviderMethod m = new ProviderMethod (
95- exec .getReturnType ().toString (),
96- exec .getSimpleName ().toString (),
97- provides .priority () == 0 ? mod .priority () : provides .priority (),
98- getInjectionName (exec .getAnnotation (Named .class )),
99- exec );
100-
101- buildInjectableParams (exec , m .parameters );
102-
103- buildCheckedExceptions (exec , m .exceptions );
104-
105- module .providerMethods .add (m );
91+ && element .getKind () == ElementKind .METHOD ) {
92+ if (provides != null ) {
93+ ExecutableElement exec = (ExecutableElement ) element ;
94+
95+ ProviderMethod m = new ProviderMethod (
96+ exec .getReturnType ().toString (),
97+ exec .getSimpleName ().toString (),
98+ provides .priority () == 0 ? mod .priority () : provides .priority (),
99+ getInjectionName (exec .getAnnotation (Named .class )),
100+ exec );
101+
102+ buildInjectableParams (exec , m .parameters );
103+
104+ buildCheckedExceptions (exec , m .exceptions );
105+
106+ module .providerMethods .add (m );
107+ } else if (alternative != null ) {
108+ ExecutableElement exec = (ExecutableElement ) element ;
109+
110+ When when = exec .getAnnotation (When .class );
111+ if (when == null ) {
112+ error ("an Alternative MUST be annotated with @When to tell when it must be activated" , exec );
113+ continue ;
114+ }
115+
116+ TypeElement alternativeTo = null ;
117+ if (alternative != null ) {
118+ try {
119+ alternative .to ();
120+ } catch (MirroredTypeException mte ) {
121+ alternativeTo = asTypeElement (mte .getTypeMirror ());
122+ }
123+ }
124+
125+ AlternativeMethod m = new AlternativeMethod (
126+ exec .getReturnType ().toString (),
127+ alternativeTo .getQualifiedName ().toString (),
128+ alternativeTo .getSimpleName ().toString (),
129+ exec .getSimpleName ().toString (),
130+ alternative .priority (),
131+ !alternative .named ().isEmpty () ? Optional .of (alternative .named ()) : Optional .<String >absent (),
132+ when .name (),
133+ when .value (),
134+ exec );
135+
136+ buildInjectableParams (exec , m .parameters );
137+
138+ buildCheckedExceptions (exec , m .exceptions );
139+
140+ module .alternativeMethods .add (m );
141+ }
106142 }
107143 }
108144
@@ -166,6 +202,11 @@ private void processComponents(RoundEnvironment roundEnv) throws IOException {
166202 private void processAlternatives (RoundEnvironment roundEnv ) throws IOException {
167203 for (Element elem : roundEnv .getElementsAnnotatedWith (Alternative .class )) {
168204 try {
205+ if (elem instanceof ExecutableElement && elem .getKind () == ElementKind .METHOD ) {
206+ // skip this annotation, if it is in a module, it will been managed by processModules
207+ continue ;
208+ }
209+
169210 if (!(elem instanceof TypeElement )) {
170211 error ("annotating element " + elem + " of type " + elem .getKind ().name ()
171212 + " with @Alternative is not supported" , elem );
@@ -274,6 +315,7 @@ private Optional<String> getInjectionName(Named named) {
274315
275316 private void generateMachineFile (ModuleClass moduleClass ) throws IOException {
276317 List <ImmutableMap <String , Object >> engines = Lists .newArrayList ();
318+ List <ImmutableMap <String , Object >> alternativesEngines = Lists .newArrayList ();
277319
278320 for (ProviderMethod method : moduleClass .providerMethods ) {
279321 engines .add (ImmutableMap .<String , Object >builder ()
@@ -289,20 +331,37 @@ private void generateMachineFile(ModuleClass moduleClass) throws IOException {
289331 .build ());
290332 }
291333
334+ for (AlternativeMethod method : moduleClass .alternativeMethods ) {
335+ alternativesEngines .add (ImmutableMap .<String , Object >builder ()
336+ .put ("componentType" , method .componentType )
337+ .put ("alternativeToComponentType" , method .alternativeType )
338+ .put ("alternativeToComponentName" , method .injectionName .or (method .alternativeName ))
339+ .put ("alternativeToComponentSimpleName" , method .alternativeName )
340+ .put ("whenName" , method .whenName )
341+ .put ("whenValue" , method .whenValue )
342+ .put ("priority" , method .priority )
343+ .put ("queriesDeclarations" , Joiner .on ("\n " ).join (buildQueriesDeclarationsCode (method .parameters )))
344+ .put ("methodName" , method .methodName )
345+ .put ("queries" , Joiner .on (",\n " ).join (buildQueriesNames (method .parameters )))
346+ .put ("parameters" , Joiner .on (",\n " ).join (buildParamFromSatisfiedBomCode (method .parameters )))
347+ .put ("exceptions" , method .exceptions .isEmpty () ? false : Joiner .on ("|" ).join (method .exceptions ))
348+ .build ());
349+ }
350+
292351 ImmutableMap <String , Object > ctx = ImmutableMap .<String , Object >builder ()
293352 .put ("package" , moduleClass .pack )
294353 .put ("machine" , moduleClass .name + "FactoryMachine" )
295354 .put ("moduleFqcn" , moduleClass .fqcn )
296355 .put ("moduleType" , moduleClass .name )
297356 .put ("priority" , moduleClass .priority )
298357 .put ("engines" , engines )
358+ .put ("alternativesEngines" , alternativesEngines )
299359 .build ();
300360
301361 generateJavaClass (moduleClass .fqcn + "FactoryMachine" , moduleMachineTpl , ctx ,
302362 Collections .singleton (moduleClass .originatingElement ));
303363 }
304364
305-
306365 private void generateMachineFile (ComponentClass componentClass , ComponentClass alternativeTo , When when ) throws IOException {
307366 ImmutableMap <String , String > ctx = ImmutableMap .<String , String >builder ()
308367 .put ("package" , componentClass .pack )
@@ -521,6 +580,7 @@ private static class ModuleClass {
521580 final String fqcn ;
522581
523582 final List <ProviderMethod > providerMethods = Lists .newArrayList ();
583+ final List <AlternativeMethod > alternativeMethods = Lists .newArrayList ();
524584 final Element originatingElement ;
525585 final String pack ;
526586 final String name ;
@@ -553,6 +613,34 @@ private static class ProviderMethod {
553613 }
554614 }
555615
616+ private static class AlternativeMethod {
617+ final Element originatingElement ;
618+ final String componentType ;
619+ final String alternativeType ;
620+ final String alternativeName ;
621+ final String methodName ;
622+ final int priority ;
623+ final Optional <String > injectionName ;
624+ final String whenName ;
625+ final String whenValue ;
626+ final List <InjectableParameter > parameters = Lists .newArrayList ();
627+ final List <String > exceptions = Lists .newArrayList ();
628+
629+ AlternativeMethod (String componentType , String alternativeType ,
630+ String alternativeName , String methodName , int priority , Optional <String > injectionName ,
631+ String whenName , String whenValue , Element originatingElement ) {
632+ this .componentType = componentType ;
633+ this .alternativeType = alternativeType ;
634+ this .alternativeName = alternativeName ;
635+ this .methodName = methodName ;
636+ this .priority = priority ;
637+ this .injectionName = injectionName ;
638+ this .whenName = whenName ;
639+ this .whenValue = whenValue ;
640+ this .originatingElement = originatingElement ;
641+ }
642+ }
643+
556644
557645 private class ServicesDeclaration {
558646 private final Set <String > declaredServices = Sets .newHashSet ();
0 commit comments