modular icon indicating copy to clipboard operation
modular copied to clipboard

UnregisteredInstance after update to 6.1.1

Open pedromellofh opened this issue 2 years ago • 29 comments

after update to modular 6.1.1 I'm getting an UnregisteredInstance after the bindings. I saw the auto_injector got some changes in da310a074e5d458324e8fe87465736c2001c9019

I've tried to add a "key" to the bindings and it only change the class it can't found. I suspect the absent 'key' may be the culprit

pedromellofh avatar Aug 30 '23 17:08 pedromellofh

Olá. Acredito que fiz a correção pra esse problema, está em beta por enquanto. Estamos avaliando.

jacobaraujo7 avatar Aug 30 '23 17:08 jacobaraujo7

O mesmo problema aqui.

allanwolski avatar Aug 31 '23 01:08 allanwolski

testei com a versão 6.2.0-beta.4, mas o problema se manteve

pedromellofh avatar Aug 31 '23 11:08 pedromellofh

Corrigido o bug: Quando era registrado uma instância em um Módulo ancestral ele ficava disponível para os filhos automaticamente. Isso gerava problemas de compreenção quando o módulo estava separado do app base. Agora recomendamos a criação de um Módulo global, exportar os binds e importar nos módulos.

jacobaraujo7 avatar Aug 31 '23 13:08 jacobaraujo7

como são binds do app_module, eu moveria para exportBinds e usaria import nos modulos filhos. isso? No caso de binds que usam outros binds do mesmo módulo, teria de importar no app_module tb?

pedromellofh avatar Aug 31 '23 14:08 pedromellofh

Isso. Mas eu sugiro que crie um Módulo como CoreModule ou CommonModule e coloque lá todos os dados globais.

jacobaraujo7 avatar Aug 31 '23 19:08 jacobaraujo7

@jacobaraujo7 nao é possivel mudar o ciclo de vida para chamar primeiramente o binds e depois o imports? Quando eu chamo meu AppModule, ele tem minhas injections globais (um controller de logs, por exemplo) que eu injeto no binds do próprio AppModule. Essa mesma classe de logs é usada em AuthModule, que eu injeto em AppModule atraves do import do AppModule. Mas quando rodo o app, da erro de que nao foi possivel encontrar essa classe de log em AuthModule, pois ele ainda nao foi injetado em AppModule.

leobidoous-gen avatar Sep 01 '23 02:09 leobidoous-gen

@jacobaraujo7 nao é possivel mudar o ciclo de vida para chamar primeiramente o binds e depois o imports? Quando eu chamo meu AppModule, ele tem minhas injections globais (um controller de logs, por exemplo) que eu injeto no binds do próprio AppModule. Essa mesma classe de logs é usada em AuthModule, que eu injeto em AppModule atraves do import do AppModule. Mas quando rodo o app, da erro de que nao foi possivel encontrar essa classe de log em AuthModule, pois ele ainda nao foi injetado em AppModule.

Sendo assim não seria melhor importar o controlador de logs a partir de um CoreModule? No ciclo de vida atual primeiro são resolvidos os exports depois os binds, mas os binds exports do módulo não sao visiveis no módulo current.

jacobaraujo7 avatar Sep 01 '23 13:09 jacobaraujo7

@jacobaraujo7 nao é possivel mudar o ciclo de vida para chamar primeiramente o binds e depois o imports? Quando eu chamo meu AppModule, ele tem minhas injections globais (um controller de logs, por exemplo) que eu injeto no binds do próprio AppModule. Essa mesma classe de logs é usada em AuthModule, que eu injeto em AppModule atraves do import do AppModule. Mas quando rodo o app, da erro de que nao foi possivel encontrar essa classe de log em AuthModule, pois ele ainda nao foi injetado em AppModule.

Sendo assim não seria melhor importar o controlador de logs a partir de um CoreModule? No ciclo de vida atual primeiro são resolvidos os exports depois os binds, mas os binds exports do módulo não sao visiveis no módulo current.

@jacobaraujo7 também tentei fazer isso, mas acontecem alguns problemas:

image image

No App Module eu estou importando as dependencias globais do meu app, as que uso em AppModule e AuthModule, como a eventLog e crashLog. No entando, quando executo o app, AuthModule nao encontra as dependencias ja injetadas em AppModule atraves do import. Como uso microfront baseado em packages, AuthModule nao tem acesso a algumas classes que eu optei por colocar apenas no base_app, como o EnvironmentEntity. O que ocorria de forma fácil no modular 5.x era a definicao dos AuthModule.exportedBinds dentro dos binds do AppModule e as dependencias ficavam no escopo global. Agora, aparentemente, a solucao seria colocar GlobalModule tambem dentro de AuthModule, mas pra que, se eu ja to colocando ele em AppModule que, em teoria, daria acesso a todos os meus outros módulos?

Outro fator que nao deveria influenciar no Modular 6.x era o commit do auto_injector, mas sempre recebo este alerta quando executo o app:

image

leobidoous-gen avatar Sep 01 '23 14:09 leobidoous-gen

@leobidoous-gen POde me mostrar aqui no discord?

jacobaraujo7 avatar Sep 04 '23 18:09 jacobaraujo7

Também estou exatamente com o mesmo problema, tenho um CoreModule no meu imports, e meu outro módulo não consegue enxergar nenhuma dependência do CoreModule. Estou com a versão flutter_modular: ^6.3.1

class AppModule extends Module {
  final Isar isar;
  final SharedPreferences sharedPreferences;

  AppModule(this.isar, this.sharedPreferences);

  @override
  List<Module> get imports => [
        CoreModule(isar, sharedPreferences),
        TicketsModule(),
      ];

  @override
  void routes(RouteManager r) {
    r.child('/', child: (context) => const HomePage());
  }
}

Meu TicketsModule.exportedBinds() não encontra Isar, nem SharedPreferences, nem outros exportedBinds do CoreModule importado no módulo pai.

Nem mesmo numa segunda tentativa, onde tentei importar o CoreModule dentro do TicketsModule. (Além de ter que passar parâmetros de classe em classe por causa da remoção do AsyncBinds)

lass TicketsModule extends Module {
  final Isar isar;
  final SharedPreferences sharedPreferences;

  TicketsModule(this.isar, this.sharedPreferences);

  @override
  List<Module> get imports => [
        CoreModule(isar, sharedPreferences),
      ];

  @override
  void exportedBinds(Injector i) {
    i.add<TicketsDataSource>(IsarTicketsDataSource.new);
    i.add<TicketsRepository>(TicketsRepositoryImpl.new);
    ...
  }

O erro é recebido:


The injector(tag: TicketsModule_Imported) is not committed.
It is recommended to call the "commit()" method after adding instances.
UnregisteredInstance: Isar not registered.
Trace: TicketsRepository->TicketsDataSource->Isar
TicketsRepository => TicketsDataSource => Isar
package:auto_injector/src/auto_injector_base.dart 261:7                    AutoInjectorImpl.get
package:auto_injector/src/auto_injector_base.dart 32:12                    Injector.call
package:casadasapostas3/core/features/tickets/tickets_module.dart 98:10    TicketsModule.exportedBinds
package:modular_core/src/tracker.dart 260:22                               _Tracker._createExportedInjector
package:modular_core/src/tracker.dart 271:30                               _Tracker._createInjector
package:modular_core/src/tracker.dart 202:25                               _Tracker.bindModule
package:flutter_modular/src/infra/services/module_service_impl.dart 25:13  ModuleServiceImpl.bind
package:flutter_modular/src/domain/usecases/bind_module.dart 17:26         BindModuleImpl.call

FernandoUFS avatar Sep 06 '23 15:09 FernandoUFS

Também estou exatamente com o mesmo problema, tenho um CoreModule no meu imports, e meu outro módulo não consegue enxergar nenhuma dependência do CoreModule. Estou com a versão flutter_modular: ^6.3.1

class AppModule extends Module {
  final Isar isar;
  final SharedPreferences sharedPreferences;

  AppModule(this.isar, this.sharedPreferences);

  @override
  List<Module> get imports => [
        CoreModule(isar, sharedPreferences),
        TicketsModule(),
      ];

  @override
  void routes(RouteManager r) {
    r.child('/', child: (context) => const HomePage());
  }
}

Meu TicketsModule.exportedBinds() não encontra Isar, nem SharedPreferences, nem outros exportedBinds do CoreModule importado no módulo pai.

Nem mesmo numa segunda tentativa, onde tentei importar o CoreModule dentro do TicketsModule. (Além de ter que passar parâmetros de classe em classe por causa da remoção do AsyncBinds)

lass TicketsModule extends Module {
  final Isar isar;
  final SharedPreferences sharedPreferences;

  TicketsModule(this.isar, this.sharedPreferences);

  @override
  List<Module> get imports => [
        CoreModule(isar, sharedPreferences),
      ];

  @override
  void exportedBinds(Injector i) {
    i.add<TicketsDataSource>(IsarTicketsDataSource.new);
    i.add<TicketsRepository>(TicketsRepositoryImpl.new);
    ...
  }

O erro é recebido:


The injector(tag: TicketsModule_Imported) is not committed.
It is recommended to call the "commit()" method after adding instances.
UnregisteredInstance: Isar not registered.
Trace: TicketsRepository->TicketsDataSource->Isar
TicketsRepository => TicketsDataSource => Isar
package:auto_injector/src/auto_injector_base.dart 261:7                    AutoInjectorImpl.get
package:auto_injector/src/auto_injector_base.dart 32:12                    Injector.call
package:casadasapostas3/core/features/tickets/tickets_module.dart 98:10    TicketsModule.exportedBinds
package:modular_core/src/tracker.dart 260:22                               _Tracker._createExportedInjector
package:modular_core/src/tracker.dart 271:30                               _Tracker._createInjector
package:modular_core/src/tracker.dart 202:25                               _Tracker.bindModule
package:flutter_modular/src/infra/services/module_service_impl.dart 25:13  ModuleServiceImpl.bind
package:flutter_modular/src/domain/usecases/bind_module.dart 17:26         BindModuleImpl.call

Peria testar na versao 6.3.2?

jacobaraujo7 avatar Sep 07 '23 16:09 jacobaraujo7

@jacobaraujo7 Houve um avanço, para o exemplo de baixo que mostrei, onde o Core é importado diretamente no submodule do TicketsModule, a dependência é encontrada com sucesso aqui, a atualização resolveu o problema nessa parte.

i.add<TicketsDataSource>(IsarTicketsDataSource.new);
i.add<TicketsRepository>(TicketsRepositoryImpl.new);

Mas agora surge outro problema logo em baixo onde uso um addInstance. Nesse ponto do addInstance não encontra as dependências.

i.addInstance(
      DetectDatabaseAndImportItAutomaticallyUseCase(
        i(),
        i(),
        i(),
        i(),
        OldAppTicketsRepositoryImpl(
          i<BlueAppOldAppTicketsDataSource>(),
        ),
        OldAppTicketsRepositoryImpl(
          i<ZenAppOldAppTicketsDataSource>(),
        ),
      ),
    );

Ele fica dando aquela mensagem de erro:

It is recommended to call the "commit()" method after adding instances.

O uso desse commit() faria o addInstance resolver as dependências?

Já para os imports do parent, não reconhece nem aí. Imagino que tenha a ver com o Phantom Dependencies fix da 6.3.0, tem alguma issue ou discussion do porquê da alteração? Porque pra fazer a migração do v5 para o v6, agora com vários submódulos, to tendo que repassar várias async dependencies resolvidas no main, pra dentro de cada módulo até chegar no submódulo que pretendo incluir com o CoreModule, há alguma recomendação pra evitar isso? Instanciar o CoreModule no main.dart como variável global e usar a instância seria uma solução adequada? Na v5 os imports passavam para os filhos, e aqui estava funcionando tudo ok dessa forma.

FernandoUFS avatar Sep 08 '23 18:09 FernandoUFS

@FernandoUFS Pq vc está usando assim em vez de:

i.add(DetectDatabaseAndImportItAutomaticallyUseCase.new);
i.add(OldAppTicketsRepositoryImpl.new);
i.add(OldAppTicketsRepositoryImpl.new);

?

jacobaraujo7 avatar Sep 09 '23 21:09 jacobaraujo7

@jacobaraujo7 Depois do meu comentário busquei o uso de Generics pra poder usar assim como você falou e consegui, só que precisei sair especificando o tipo de classe em classe até chegar onde eu queria.

O motivo de eu ter usado como mandei anteriormente, era pra que na injeção de dependência eu pudesse especificar qual OldAppTicketsDataSource o use case iria utilizar, sem ficar passando o tipo genérico. Me fez escrever menos código na V5 do modular.

O construtor do meu DetectDatabaseAndImportItAutomaticallyUseCase recebe dois repositories, onde o tipo do repository é o mesmo: OldAppTicketsRepositoryImpl, mas o tipo que os dois repositories recebem do datasource é diferente, por isso o:

i<BlueAppOldAppTicketsDataSource>(),
i<ZenAppOldAppTicketsDataSource>(),

Perceba que no exemplo que você deu, você colocou repetido:

i.add(OldAppTicketsRepositoryImpl.new);
i.add(OldAppTicketsRepositoryImpl.new);

Resolvi na V6 da seguinte forma:

class DetectDatabaseAndImportItAutomaticallyUseCase<TDataSource1 extends OldAppTicketsDataSource, TDataSource2 extends OldAppTicketsDataSource> {
  final ...;
  final ...;
  final TicketsRepository ticketsRepository;
  final OldAppTicketsRepository<TDataSource1> app1OldAppTicketsRepository;
  final OldAppTicketsRepository<TDataSource2> app2OldAppTicketsRepository;
  final SettingsRepository settingsRepository;

  ... constructor
}
i.add(DetectDatabaseAndImportItAutomaticallyUseCase<BlueAppOldAppTicketsDataSource, ZenAppOldAppTicketsDataSource>.new);

FernandoUFS avatar Sep 11 '23 11:09 FernandoUFS

@FernandoUFS Quando for assim vc pode usar uma função anonima:

i.add(() => DetectDatabaseAndImportItAutomaticallyUseCase<BlueAppOldAppTicketsDataSource, ZenAppOldAppTicketsDataSource>());

jacobaraujo7 avatar Sep 11 '23 13:09 jacobaraujo7

Obrigado pela dica @jacobaraujo7, deu certo com a função anônima. Consegui fazer do jeito antigo com ela.

E sobre a motivação da remoção do AsyncBind há algum post ou vídeo sobre isso? e os meios indicados para fazer no Modular v6?

Na v5 eu tinha, e agora preciso resolver as instâncias no main e passar via construtor de módulo até chegar no último submodulo, e como é algo do Core eu to precisando repassar pra vários submódulos, já que o import do pai não passa mais para os filhos. Ainda n achei um jeito legal de fazer isso sem repetição.

class CoreModule extends Module {
  @override
  List<Bind<Object>> get binds => [
        AsyncBind((i) => SharedPreferences.getInstance(), export: true),
        AsyncBind((i) async {
          final dir = await getApplicationDocumentsDirectory();
          Isar isar = await Isar.open(
            [IsarTicketSchema, IsarSelectionSchema, IsarTagSchema, IsarMatchResultSchema],
            directory: dir.path,
          );
          return isar;
        }, export: true),
      ];
}

FernandoUFS avatar Sep 11 '23 17:09 FernandoUFS

@FernandoUFS Veja este vídeo do Jacob: https://www.youtube.com/watch?v=xAiq8DzR65s A partir do minuto: 1h 10m 32s

eduardoflorence avatar Sep 11 '23 17:09 eduardoflorence

6.3.2 com modulo somente de exports funcionou aqui

pedromellofh avatar Oct 30 '23 18:10 pedromellofh

Here is my case where imports broke after 6.1.1. I had modules that had dependencies on each other.

For example Module1 depends on Module2

class Class1_1 {}

class Class1_2 {
  Class1_2(this.class1);

  final Class2_2 class1;
}

class Module1 extends Module {
  @override
  void exportedBinds(Injector i) {
    i.add(Class1_1.new);
    i.add(Class1_2.new); /// needs [Class2_2] from [Module2]
  }
}

and Module2 depends on Module1

class Class2_1 {
  Class2_1(this.class1);

  final Class1_1 class1;
}

class Class2_2 {}

class Module2 extends Module {
  @override
  void exportedBinds(Injector i) {
    i.add(Class2_1.new); /// needs [Class1_1] from [Module1]
    i.add(Class2_2.new);
  }
}

Before version 6 I could just put them in one AppModule module, but now I am getting UnregisteredInstance error

class AppModule extends Module {
  @override
  List<Module> get imports => [ /// these modules cannot see [exportedBinds] of each other
        Module1(),
        Module2(),
      ];
}

And I cannot use imports in Module1 and Module2, because it will cause StackOverflowError due recursion.

As a solution it would be great to give us a option, that makes modules, defined in imports in AppModule to see exportedBinds of each other like it was before.

0x384c0 avatar Dec 12 '23 13:12 0x384c0

@0x384c0, create a third module and put the classes in common from modules 1 and 2. Import this third module into modules 1 and 2

eduardoflorence avatar Dec 12 '23 14:12 eduardoflorence

Estou tendo um problema similar, mas um pouco diferente. Tenho um módulo global que exporta as binds globais, porém o erro parece estar atrelado a ordem de declaração dos Binds que contêm key. Por exemplo, tenho 3 binds com keys, o primeiro bind(com key) da erro ao chamar a classe em questão. Se eu remover essa key e deixar rolar a injeção por tipagem a segunda key, que nesse caso seria a primeira, começa a dar erro.

image image image

Alguém sabe o que pode ser?

OBS: Estou utilizando a versão mais recente, que no momento é a 6.3.2

GabrielGoliveira04 avatar Feb 14 '24 18:02 GabrielGoliveira04

Também estou enfrentando algumas dificuldades para conseguir atualizar da versão 5 para a 6.

Quem fica responsável pelo ciclo de vida dos binds de módulos importados? Pois nos meus testes eles nunca são removidos da memória, mesmo quando ocorre o dispose do módulo proprietário ou do módulo que fez o import.

Na versão 5 eu não precisava usar import porque era possível "reaproveitar" o bind nos demais módulos. @jacobaraujo7, consegue dar um help por favor?

allanwolski-openco avatar Aug 26 '24 13:08 allanwolski-openco