Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UnregisteredInstance after update to 6.1.1 #895

Open
pedromellofh opened this issue Aug 30, 2023 · 29 comments
Open

UnregisteredInstance after update to 6.1.1 #895

pedromellofh opened this issue Aug 30, 2023 · 29 comments
Labels
new New issue request attention

Comments

@pedromellofh
Copy link

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

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 pedromellofh added the new New issue request attention label Aug 30, 2023
@jacobaraujo7
Copy link
Contributor

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

@allanwolski
Copy link

O mesmo problema aqui.

@pedromellofh
Copy link
Author

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

@jacobaraujo7
Copy link
Contributor

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.

@pedromellofh
Copy link
Author

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?

@jacobaraujo7
Copy link
Contributor

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

@leobidoous-gen
Copy link

@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.

@jacobaraujo7
Copy link
Contributor

@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.

@leobidoous-gen
Copy link

leobidoous-gen commented Sep 1, 2023

@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

@jacobaraujo7
Copy link
Contributor

@leobidoous-gen POde me mostrar aqui no discord?

@FernandoUFS
Copy link

FernandoUFS commented Sep 6, 2023

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

@jacobaraujo7
Copy link
Contributor

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?

@FernandoUFS
Copy link

FernandoUFS commented Sep 8, 2023

@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.

@jacobaraujo7
Copy link
Contributor

jacobaraujo7 commented Sep 9, 2023

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

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

?

@FernandoUFS
Copy link

FernandoUFS commented Sep 11, 2023

@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);

@jacobaraujo7
Copy link
Contributor

jacobaraujo7 commented Sep 11, 2023

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

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

@FernandoUFS
Copy link

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),
      ];
}

@eduardoflorence
Copy link

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

@pedromellofh
Copy link
Author

6.3.2 com modulo somente de exports funcionou aqui

@0x384c0
Copy link

0x384c0 commented Dec 12, 2023

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.

@eduardoflorence
Copy link

@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

@GabrielGoliveira04
Copy link

GabrielGoliveira04 commented Feb 14, 2024

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

@allanwolski-openco
Copy link

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?

@Allanfd12
Copy link

image
estou com problemas relacionados ao binding, o modular não consegue entender que o BaseOptions é opcional e que não precisa ser informado para construir o objeto Dio
image

aparentemente o código abaixo contorna o problema
image

seria iteressante, para facilitar a migração modular 5 => 6, que o modular validasse antes de estourar o erro UnregisteredInstance, se essa dependencia pode ser nula e construir o objeto caso seja possível

@Allanfd12
Copy link

image

image
Seria interessante que todas as interfaces de uma dada classe informada, fossem instanciadas quando o tipo do binding não for informado.

Ao chamar i.add(HomeDataSourceImpl.new); o modular não consegue resolver uma dependencia de "HomeDataSource", mesmo que HomeDataSourceImpl implemente HomeDataSource;

Ao usar i.add(HomeDataSourceImpl.new); o modular para de reconhecer HomeDataSourceImpl como uma dependencia cadastrada e só reconhece o HomeDataSource.

@Allanfd12
Copy link

image
binds funcionam para dependências dentro do módulo e apenas dentro do módulo.
exportedBinds funcionam para dependências fora do módulo e apenas fora do módulo.

quando eu defino uma dependencia para funcionar dentro e fora do módulo (Copiando ela no binds e no exportedBinds) o modular retorna um erro indicando que essa dependência já foi inserida na lista de injections
image

O que eu faço caso eu precise de uma dependência que atue dentro e fora de um determinado módulo? Especialmente levando em conta que filhos de um módulo não herdam as dependências de seus pais?

@eduardoflorence
Copy link

image binds funcionam para dependências dentro do módulo e apenas dentro do módulo. exportedBinds funcionam para dependências fora do módulo e apenas fora do módulo.

quando eu defino uma dependencia para funcionar dentro e fora do módulo (Copiando ela no binds e no exportedBinds) o modular retorna um erro indicando que essa dependência já foi inserida na lista de injections image

O que eu faço caso eu precise de uma dependência que atue dentro e fora de um determinado módulo? Especialmente levando em conta que filhos de um módulo não herdam as dependências de seus pais?

@Allanfd12, existe um AuthController dentro de CoreModule também? Se tiver, não precisa fazer bind e nem exported dele novamente, pois ele já vem para você no imports

@Allanfd12
Copy link

@Allanfd12, existe um AuthController dentro de CoreModule também? Se tiver, não precisa fazer bind e nem exported dele novamente, pois ele já vem para você no imports

Não existe um AuthController dentro do CoreModule, mas colocar as dependências todas no CoreModule resolve o problema.
Porém perde um pouco a intenção de separar as dependências de acordo com os módulos

@Sarrius
Copy link

Sarrius commented Dec 18, 2024

binds funcionam para dependências dentro do módulo e apenas dentro do módulo. exportedBinds funcionam para dependências fora do módulo e apenas fora do módulo.

quando eu defino uma dependencia para funcionar dentro e fora do módulo (Copiando ela no binds e no exportedBinds) o modular retorna um erro indicando que essa dependência já foi inserida na lista de injections image

O que eu faço caso eu precise de uma dependência que atue dentro e fora de um determinado módulo? Especialmente levando em conta que filhos de um módulo não herdam as dependências de seus pais?

totally agree it feels nonsense to me as well. We need to have inner binds to be available as dependencies for exported binds. It should feel intuitive but for some reason it is not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new New issue request attention
Projects
None yet
Development

No branches or pull requests