unable to register an abstract class in using injectable and get_it packages

285

ok, so I guess injectable can't see what the class implements so you have to make it explicit. also, I missed that @dev isn't built in, you have to make it.

So this is the proper way to use the decorations

@Environment('dev')
@Injectable(as: IRandomQuantityRepository)
class DevRandomQuantityRepository implements IRandomQuantityRepository {
  const DevRandomQuantityRepository();

  @override
  Future<Either<QuantFailure, Quantity>> getRandomQuantity() async =>
      right(Quantity(Amount(900.0001), Decimal(4)));
}

and that way this does work:

configureInjection(Env.dev);
final mockRandomQuantity = getIt<IRandomQuantityRepository>();
await mockRandomQuantity.getRandomQuantity();
// 90
Share:
285
MetaStack
Author by

MetaStack

Updated on January 05, 2023

Comments

  • MetaStack
    MetaStack 10 months

    I'm using injectable and get_it in flutter dart (following the very popular Reso coder)

    I have a simple abstract class:

    import 'package:injectable/injectable.dart';
    
    //@injectable
    abstract class IRandomQuantityRepository {
      Future<int> getRandomQuantity();
    }
    

    and I have two simple concrete implementations of it:

    import 'package:injectable/injectable.dart';
    
    @dev
    @injectable
    class DevRandomQuantityRepository implements IRandomQuantityRepository {
      const DevRandomQuantityRepository();
    
      @override
      Future<int> getRandomQuantity() async => 90;
    }
    

    and

    import 'dart:math';
    import 'package:injectable/injectable.dart';
    
    @prod
    @injectable
    class RandomQuantityRepository implements IRandomQuantityRepository {
      const RandomQuantityRepository();
    
      @override
      Future<int> getRandomQuantity() async => Random().nextInt(100);
    }
    

    Lastly, I have an injection.dart:

    import 'package:get_it/get_it.dart';
    import 'package:injectable/injectable.dart';
    import 'package:moontreeapp/injection.config.dart';
    
    final GetIt getIt = GetIt.instance;
    
    @InjectableInit(preferRelativeImports: false)
    void configureInjection(String env) {
      $initGetIt(getIt, environment: env);
    }
    
    abstract class Env {
      static const prod = 'prod';
      static const dev = 'dev';
    }
    

    besides all that I have a bloc that wants to use stuff:

    @injectable
    class RandomQuantityBloc
        extends Bloc<RandomQuantityEvent, RandomQuantityState> {
      final IRandomQuantityRepository _quantityFacade; // notice this final...
    

    doesn't that look good? I think so. So then I run this command to make the generated code flutter pub run build_runner watch

    But I get a message:

    [RandomQuantityBloc] depends on unregistered type [IRandomQuantityRepository]... Did you forget to annotate the above class(s) or their implementation with @injectable? or add the right environment keys?

    Ok, so that's cool, lets add it to the interface:

    import 'package:injectable/injectable.dart';
    
    @injectable // <-- added 
    abstract class IRandomQuantityRepository {
      Future<int> getRandomQuantity();
    }
    

    but then I get a new error:

    > [IRandomQuantityRepository] is abstract and can not be registered directly! 
    > if it has a factory or a create method annotate it with @factoryMethod
    > 14 │ abstract class IRandomQuantityRepository {
    >    │                ^^^^^^^^^^^^^^^^^^^^^^^^^
    

    In the past I've handled dependency injection manually, so I'm new to these packages, what am I missing here?

    Besides all that, the real issue is that I can't switch the injection based on the environment. I can use get_it to get a concrete dependency but not one based on environment like in this test:

        /// has no effect:
        configureInjection(Env.dev);
    
        /// gets prod version:
        final devRandomQuantity = getIt<RandomQuantityRepository>();
    

    So something about this whole set up isn't configuring the Injections correctly... What am I missing?

    One final thing that might be useful is to see the generated code:

    // GENERATED CODE - DO NOT MODIFY BY HAND
    
    // **************************************************************************
    // InjectableConfigGenerator
    // **************************************************************************
    
    import 'package:get_it/get_it.dart' as _i1;
    import 'package:injectable/injectable.dart' as _i2;
    import 'package:moontreeapp/application/quantity/bloc/randomquantity_bloc.dart'
        as _i5;
    import 'package:moontreeapp/domain/quantity/i_randomquantity_repository.dart' as _i6;
    import 'package:moontreeapp/infrastructure/quantity/dev_randomquantity_repository.dart'
        as _i3;
    import 'package:moontreeapp/infrastructure/quantity/mock_randomquantity_repository.dart'
        as _i4;
    import 'package:moontreeapp/infrastructure/quantity/randomquantity_repository.dart'
        as _i7;
    
    const String _dev = 'dev';
    const String _prod = 'prod';
    // ignore_for_file: unnecessary_lambdas
    // ignore_for_file: lines_longer_than_80_chars
    /// initializes the registration of provided dependencies inside of [GetIt]
    _i1.GetIt $initGetIt(_i1.GetIt get,
        {String? environment, _i2.EnvironmentFilter? environmentFilter}) {
      final gh = _i2.GetItHelper(get, environment, environmentFilter);
      gh.factory<_i3.DevRandomQuantityRepository>(
          () => _i3.DevRandomQuantityRepository(),
          registerFor: {_dev});
      gh.factory<_i5.RandomQuantityBloc>(
          () => _i5.RandomQuantityBloc(get<_i6.IRandomQuantityRepository>()));
      gh.factory<_i7.RandomQuantityRepository>(() => _i7.RandomQuantityRepository(),
          registerFor: {_prod});
      return get;
    }
    
    

    Do I put @injectable on abstract classes or not?