unable to register an abstract class in using injectable and get_it packages
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
MetaStack
Updated on January 05, 2023Comments
-
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?