9
respostas

[Dúvida] Exceção: NullPointerException(CategoryRepository.saveAll(java.lang.Iterable)

durante a pratica do desafio, encontrei a seguinte exceção:
java.lang.NullPointerException: Cannot invoke "com.example.gerenciador_pedidos.repository.CategoryRepository.saveAll(java.lang.Iterable)" because "this.categoryRepository" is null

a exceção redireciona a causa para a classe Main:

//Main

@Component
public class GerenciadorPedidos{
//nome refatorado
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private CategoryRepository categoryRepository;
   
    public void Gerenciador() {
    //metodo refatorado
        Category eletronics = new Category(1L, "Eletronics");
        Category tools = new Category(2L, "Tools");

        Product notebook = new Product(4500.0,"Notebook", eletronics);
        Product smartphone = new Product(2500.0, "Smartphone", eletronics);
        Product watch = new Product(750.0, "Watch", eletronics);
        Product powerScrewdriver = new Product(300.0, "Power Screwdriver", tools);

        eletronics.setProduct(List.of(notebook, smartphone, watch));
        tools.setProduct(List.of(powerScrewdriver));

        categoryRepository.saveAll(List.of(eletronics, tools));

        System.out.println("Categorias e produtos: ");
        categoryRepository.findAll().forEach(category -> {
            System.out.println("Categorias: " + category.getName());
            category.getProduct().forEach(product -> System.out.println("Produtos: " + product.getName()));
        });
     //   Requests requests = new Requests(1L, LocalDate.now());
    }
}
//modelos:
@Entity
public class Category {

    @Id
    private Long id;

    private String name;

    @OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
    private List<Product> product;

    public Category(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public List<Product> getProduct() {
        return product;
    }

    public void setProduct(List<Product> product) {
        this.product = product;
    }

    public Category() {
    }
}


@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(nullable = false, unique = true)
    private String name;
    @Column(name = "value")
    private double price;
    @ManyToOne
    @JoinColumn(name = "category_id")
    private Category category;

    public Product(double price, String name, Category category) {
        this.price = price;
        this.name = name;
        this.category = category;
    }
    public Long getId() {
        return id;
    }
    public String getName() {
        return name;
    }
    public double getPrice() {
        return price;
    }
    public Category getCategory() {
        return category;
    }

    public Product() {
    }
}

//Repositórios:
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {}

@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {}
9 respostas

Olá Davi! Como vai?

O problema está ocorrendo porque a instância de CategoryRepository está nula no momento em que você tenta chamá-la no método Main. Isso geralmente acontece quando o Spring não consegue injetar a dependência corretamente.

Aqui estão algumas sugestões para resolver o problema:

  1. Verifique a Anotação @Component: Certifique-se de que a classe Main está sendo gerenciada pelo Spring. A anotação @Component está correta, mas você precisa garantir que a classe Main está sendo escaneada pelo Spring. Isso pode ser feito verificando se o pacote onde a classe Main está localizada está incluído no escaneamento de componentes do Spring.

  2. Construtor da Classe Main: Parece que você está tentando usar um método chamado Main como construtor, mas em Java, o construtor deve ter o mesmo nome da classe e não deve ter um tipo de retorno. Corrija o nome do método para que seja o construtor da classe:

    @Component
    public class Main {
        @Autowired
        private ProductRepository productRepository;
        @Autowired
        private CategoryRepository categoryRepository;
    
        // Construtor sem tipo de retorno
        public Main() {
            // Seu código aqui...
        }
    }
    
  3. Inicialização do Contexto Spring: Certifique-se de que sua aplicação está sendo executada em um contexto Spring. Se você estiver usando uma aplicação Spring Boot, a classe principal deve estar anotada com @SpringBootApplication e você deve iniciar a aplicação com SpringApplication.run().

  4. Teste a Injeção de Dependência: Verifique se as dependências estão sendo injetadas corretamente. Você pode adicionar um método @PostConstruct na sua classe Main para verificar se os repositórios estão sendo injetados corretamente:

    @PostConstruct
    public void init() {
        if (categoryRepository == null) {
            System.out.println("categoryRepository não foi injetado!");
        } else {
            System.out.println("categoryRepository foi injetado com sucesso!");
        }
    }
    

Essas são algumas dicas que podem ajudar a resolver o problema.

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado ✓.

Boa noite.
após usar suas dicas, descobri mais alguns problemas, ainda relacionado á injeção de dependencia:

  • A classe Main não estava sendo escaneada.
    • Quando foi feita a correção do método para construtor, passou a retornar mais duas exceções: "BeanCreationException e "BeanInstantiationException".
  • Minha aplicação está sendo está sendo executada num ambiente Spring, especificamente "Spring sem Boot"
  • As dependencias não foram injetadas, e "init()" retorna false na inicialização, e true ao finalizar.

Não tenho certeza como posso solucionar as novas exceções, porém no modelo anterior (method), decidi corrigir o nome para evitar confusão futura. Aceito orientação na possivel resolução da Exceção.

Oi, Davi!

O erro NullPointerException continua porque, no seu cenário com Spring sem Boot, a injeção com @Autowired não funciona automaticamente se a classe GerenciadorPedidos não for registrada corretamente no ApplicationContext.

A solução aqui é clara: você precisa criar e registrar manualmente o contexto do Spring e obter o bean da classe GerenciadorPedidos, para que as injeções @Autowired funcionem.

Veja como ajustar isso:

  1. Crie uma classe de configuração ou use uma já existente com @ComponentScan:

    
     @Configuration
     @ComponentScan(basePackages = "com.example.gerenciador_pedidos")
     public class AppConfig {
     }
     
  2. Crie uma classe Main para iniciar o contexto e executar o método desejado:

    
     public class Main {
         public static void main(String[] args) {
             AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    
             GerenciadorPedidos gerenciador = context.getBean(GerenciadorPedidos.class);
             gerenciador.executar(); // método renomeado para refletir que é uma ação, não um construtor
    
             context.close();
         }
     }
     
  3. Altere o método Gerenciador() para um nome válido de método (não construtor):

    
     @Component
     public class GerenciadorPedidos {
         @Autowired
         private ProductRepository productRepository;
    
         @Autowired
         private CategoryRepository categoryRepository;
    
         public void executar() {
             Category eletronics = new Category(1L, "Eletronics");
             Category tools = new Category(2L, "Tools");
    
             Product notebook = new Product(4500.0,"Notebook", eletronics);
             Product smartphone = new Product(2500.0, "Smartphone", eletronics);
             Product watch = new Product(750.0, "Watch", eletronics);
             Product powerScrewdriver = new Product(300.0, "Power Screwdriver", tools);
    
             eletronics.setProduct(List.of(notebook, smartphone, watch));
             tools.setProduct(List.of(powerScrewdriver));
    
             categoryRepository.saveAll(List.of(eletronics, tools));
    
             System.out.println("Categorias e produtos: ");
             categoryRepository.findAll().forEach(category -> {
                 System.out.println("Categorias: " + category.getName());
                 category.getProduct().forEach(product -> System.out.println("Produtos: " + product.getName()));
             });
         }
     }
     

Resumo do que foi feito:

  • Você passou a usar um ApplicationContext padrão do Spring para carregar os beans.
  • O método Gerenciador() foi renomeado para executar() para evitar conflito com o construtor.
  • A anotação @ComponentScan garante que GerenciadorPedidos seja reconhecido como bean.

Fico à disposição.

Boa tarde e obrigado pela ajuda desde já!
após registrar as mudanças no código, dessa vez retorna o erro:

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-08-05T17:05:25.063-03:00 ERROR 24629 --- [gerenciador-pedidos] [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class


Action:

Consider the following:
    If you want an embedded database (H2, HSQL or Derby), please put it on the classpath.
    If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).

Pela descrição do erro, suponho que seja algo haver com as propriedades da aplicação:

//application.properties

spring.application.name=gerenciador-pedidos
hibernate.dialect=org.hibernate.dialect.HSQLDialect
//username e senha omitidos

spring.datasource.url=jdbc:postgresql://localhost/gerenciador-pedidos
hibernate.transaction.jta.platform
spring.jpa.hibernate.ddl-auto=update
spring.datasource.driver-class-name=org.postgresql.Driver

Tentei procurar sobre o erro e não encontrei informação sobre a integraç

Oi, Davi! Perdão pela demora em responder!

O erro indica que o Spring não conseguiu configurar o DataSource porque a URL e o driver não foram interpretados corretamente no application.properties. No seu arquivo, há propriedades com prefixos errados e chaves sem valor. Corrija assim:


spring.application.name=gerenciador-pedidos

spring.datasource.url=jdbc:postgresql://localhost:5432/gerenciador-pedidos
spring.datasource.username=SEU_USUARIO
spring.datasource.password=SUA_SENHA
spring.datasource.driver-class-name=org.postgresql.Driver

spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update

Ajustes importantes:

  • Use o prefixo spring.jpa.database-platform em vez de hibernate.dialect.
  • Adicione a porta do PostgreSQL na URL (por padrão, 5432).
  • Remova linhas sem valor como hibernate.transaction.jta.platform.
  • Certifique-se de que o driver do PostgreSQL (org.postgresql.Driver) está no classpath (dependência no pom.xml ou build.gradle).

Depois disso, ao iniciar a aplicação, o Spring deve conseguir criar a conexão e inicializar o contexto sem esse erro.

Fico à disposição.

Boa tarde.
seguindo sua orientação, o erro continuou sendo o mesmo. todas as dependencias necessárias estão no pom.xml

após outra inspeção no console notei dois avisos, um deles contendo a exceção anterior:

//antes de inicializar

2025-08-12T16:34:19.570-03:00  WARN 15084 --- [gerenciador-pedidos] [           main] org.hibernate.orm.deprecation            : HHH90000025: PostgreSQLDialect does not need to be specified explicitly using 'hibernate.dialect' (remove the property setting and it will be selected by default)
//após a inicialização.

2025-08-12T16:26:24.531-03:00  WARN 14044 --- [gerenciador-pedidos] [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Failed to initialize dependency 'dataSourceScriptDatabaseInitializer' of LoadTimeWeaverAware bean 'entityManagerFactory': Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: Failed to instantiate [com.zaxxer.hikari.HikariDataSource]: Factory method 'dataSource' threw exception with message: Failed to determine a suitable driver class

Olá, Davi!

Nesse caso, peço que envie todo o seu projeto para um repositório remoto, GitHub, por exemplo, e compartilhe o link comigo, assim poderei testar as várias soluções para esse problema.

Fico no aguardo!

Segue abaixo o link do repositório:

https://github.com/RaviGoldenheart/gerenciador-pedidos

Boa tarde, Davi!

Realmente investi um certo tempo para entender o que estava causando esse problema, desde o primeiro momento achei que o problema está no pom.xml com as dependências ou no application.properties, mas depois de um bom tempo entendi que não está lá.

O problema está relacionado a sua classe AppConfig, por conta dela você está subindo 2 ApplicationContexts. O Spring Boot sobe um contexto puxando a configuração padrão, mas no seu run(...) você cria outro contexto com new AnnotationConfigApplicationContext(AppConfig.class). Esse segundo contexto não tem autoconfiguração, então não cria o DataSource → daí o erro de “'url' attribute is not specified” quando seus beans rodam nele.

Então, a primeira correção é apagar o AppConfig e alterar o arquivo GerenciadorPedidosApplication para ficar assim:

package com.example.gerenciador_pedidos;

import com.example.gerenciador_pedidos.service.GerenciadorPedidos;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class GerenciadorPedidosApplication {

    public static void main(String[] args) {
        SpringApplication.run(GerenciadorPedidosApplication.class, args);
    }

    @Bean
    CommandLineRunner run(GerenciadorPedidos gerenciador) {
        return args -> gerenciador.executar();
    }
}

Agora, outro problema que apareceu ao testar a sua aplicação foi sobre o GereciadorPedidos, o seu Service do projeto. Nele é necessário adicionar a annotation @Transactional para conseguir realizar a operação:

@PostConstruct
    @Transactional
    public void init() {
        if (categoryRepository == null) {
            System.out.println("categoryRepository não foi injetado!");
        } else {
            System.out.println("categoryRepository foi injetado com sucesso!");
        }
    }

Por fim, em complemento, na solução do problema, é necessário adicionar o tipo de fetch utilizado na relação do Product em Category como EAGER. Segue um exemplo de como deve ficar:

package com.example.gerenciador_pedidos.model;

import jakarta.persistence.*;

import java.util.List;

@Entity
public class Category {

    @Id
    private Long id;

    private String name;

    @OneToMany(mappedBy = "category", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Product> product;

    // Resto do código omitido

Espero ter ajudado!