javadependency-injectionguiceassisted-inject

Using @Assisted inject with multiple params of same Type (@Named params)


my problem boils down to using @Assisted with two string arguments to the factory. The problem is that because Guice treats type as the identification mechanism for parameters, both parameters are the same, and I get a configuration error.

Some Code:

public class FilePathSolicitingDialog {

    //... some fields

    public static interface Factory {
        public FilePathSolicitingDialog make(Path existingPath,
                                             String allowedFileExtension,
                                             String dialogTitle);
    }

    @Inject
    public FilePathSolicitingDialog(EventBus eventBus,
                                    SelectPathAndSetTextListener.Factory listenerFactory,
                                    FilePathDialogView view,
                                    @Assisted Path existingPath,
                                    @Assisted String allowedFileExtension,
                                    @Assisted String dialogTitle) {
        //... typical ctor, this.thing = thing
    }

    // ... methods
}

The problem lies in the double-strings parameters.

I've tried tagging each string with separate @Named("as appropriate") annotations, but that just leads to more configuration errors. From the sound of those errors they don't want binding annotations on the factory class, so I have not tried custom binding annotations.

The simple and noisy solution is to create a simple argument class to contain those three assisted values, and simply inject that:

    public static class Config{
        private final Path existingPath;
        private final String allowedFileExtension;
        private final String dialogTitle;

        public Config(Path existingPath, String allowedFileExtension, String dialogTitle){
            this.existingPath = existingPath;
            this.allowedFileExtension = allowedFileExtension;
            this.dialogTitle = dialogTitle;
        }
    }

    public static interface Factory {
        public FilePathSolicitingDialogController make(Config config);
    }

    @Inject
    public FilePathSolicitingDialogController(EventBus eventBus,
                                              SelectPathAndSetTextListener.Factory listenerFactory,
                                              FilePathDialogView view,
                                              @Assisted Config config) {
        //reasonably standard ctor, some this.thing = thing
        // other this.thing = config.thing
    }
}

This works and is likely to be fairly bug-free but is noisy. Some way to get rid of that nested static class would be nice.

Thanks for any help!


Solution

  • Have a look at this documentation (previously here):

    Making parameter types distinct

    The types of the factory method's parameters must be distinct. To use multiple parameters of the same type, use a named @Assisted annotation to disambiguate the parameters. The names must be applied to the factory method's parameters:

    public interface PaymentFactory {
       Payment create(
           @Assisted("startDate") Date startDate,
           @Assisted("dueDate") Date dueDate,
           Money amount);
     }
    

    ...and to the concrete type's constructor parameters:

    public class RealPayment implements Payment {
       @Inject
       public RealPayment(
          CreditService creditService,
          AuthService authService,
          @Assisted("startDate") Date startDate,
          @Assisted("dueDate") Date dueDate,
          @Assisted Money amount) {
         ...
       }
     }