Solucionado (ver solução)
Solucionado
(ver solução)
11
respostas

@org.springframework.beans.factory.annotation.Autowired(required=true)

Alguém teve que lidar com esse erro?

Erro:


APPLICATION FAILED TO START


Description:

Field topicoRepository in br.com.alura.forum.controller.TopicosController required a bean of type 'br.com.alura.forum.repository.TopicoRepository' that could not be found.

The injection point has the following annotations:

- @org.springframework.beans.factory.annotation.Autowired(required=true)

Action:

Consider defining a bean of type 'br.com.alura.forum.repository.TopicoRepository' in your configuration.

--------classe

package br.com.alura.forum.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;

import br.com.alura.forum.dto.TopicoDto; import br.com.alura.forum.modelo.Topico; import br.com.alura.forum.repository.TopicoRepository;

@RestController public class TopicosController {

@Autowired
private TopicoRepository topicoRepository;

@RequestMapping("/topicos")
public List<TopicoDto> lista(){
    List<Topico> topicos = topicoRepository.findAll();        
    return TopicoDto.converter(topicos);
}

}

-------interface

package br.com.alura.forum.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import br.com.alura.forum.modelo.Topico;

public interface TopicoRepository extends JpaRepository<Topico, Long>{

}


Se eu inserir @ComponentScan("br.com.alura.forum.repository") na classe ForumApplication o projeto compila, mas não consigo acessar /topicos

11 respostas

Oi Felipe,

Em qual pacote está a sua classe main(ForumApplication)?

Estou tendo o mesmo problema

Verifiquem se a classe main(ForumApplication) está no pacote: br.com.alura.forum

Desculpe não ter respondido Rodrigo, acabei fazendo o download do projeto e segui em frente. Eu tinha a classe no pacote br.com.alura.forum, modifiquei o @ComponentScan, mas nada adiantou.

Acredito que o erro poderia estar relacionado ao momento que criei o meu projeto, pois criei no SpringToolSuite e posso ter selecionado algo errado.

package br.com.alura.forum;

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; import org.springframework.data.web.config.EnableSpringDataWebSupport;

@SpringBootApplication @EnableSpringDataWebSupport // Com essa anotação habilitamos esse suporte, para o Spring pegar da requisição, dos parâmetros da url os campos, as informações de paginação e ordenação, e repassar isso para o Spring data @EnableCaching // habilita o uso de cache na aplicacao public class ForumApplication {

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

}

Continuo com o problema

Description:

Field topicoRepository in br.com.alura.forum.controller.TopicosController required a bean of type 'br.com.alura.forum.repository.TopicoRepository' that could not be found.

The injection point has the following annotations:

- @org.springframework.beans.factory.annotation.Autowired(required=true)

Action:

Consider defining a bean of type 'br.com.alura.forum.repository.TopicoRepository' in your configuration.

Process finished with exit code 0

package br.com.alura.forum.controller;

import br.com.alura.forum.controller.dto.DetalhesDoTopicoDto;
import br.com.alura.forum.controller.dto.TopicoDto;
import br.com.alura.forum.controller.form.AtualizacaoTopicoForm;
import br.com.alura.forum.controller.form.TopicoForm;
import br.com.alura.forum.modelo.Curso;
import br.com.alura.forum.modelo.Topico;
import br.com.alura.forum.repository.CursoRepository;
import br.com.alura.forum.repository.TopicoRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.transaction.annotation.Transactional;


import javax.validation.Valid;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * O problema é que em todos os métodos a URL vai se repetir. Se um dia eu quiser alterar,
 * vou ter que alterar em todos os métodos. Podemos tirar a anotação @RequestMapping(Value=
 * "/topicos", method = RequestMethod.GET) de cima do método e colocar em cima da classe.
 * Mas aí, na classe, não vou colocar o método, vou colocar só a URL. Então, é como se
 * disséssemos ao Spring: o TopicosController responde às aquisições que começam com "/
 *
 * E aí, no método cadastrar eu faço a mesma coisa. Só que aí é POST ao invés de GET, porque estou
 * postando uma informação, fazendo um cadastro. Dessa maneira, não teria mais conflito. O Spring
 * sabe que a URL é a mesma, mas os métodos são diferentes.
 */

@RestController
@RequestMapping("/topicos")//a mesma url vale para o metodo get e para o post
public class TopicosController {


    @Autowired
    private TopicoRepository topicoRepository;
    @Autowired
    private CursoRepository cursoRepository;


    @GetMapping
    @Cacheable(value = "listaDeTopicos")
    public Page<TopicoDto>lista(@RequestParam(required = false) String nomeCurso,
                           @PageableDefault(sort="id",direction = Sort.Direction.DESC,size=10) Pageable paginacao){


        if(nomeCurso==null){
            Page<Topico> topicos =topicoRepository.findAll(paginacao);
            return TopicoDto.converter(topicos);
        }else{
            Page<Topico> topicos = topicoRepository.findByCurso_Nome(nomeCurso,paginacao);
            return TopicoDto.converter(topicos);
        }
    }
    //Funcionamento web - informacoes cadastradas pelo usuario sao armazenadas em Json e o spring chama o "JACKSON"
    //para converter em TopicForm
    @PostMapping
    @Transactional
     public ResponseEntity<TopicoDto> cadastrar(@RequestBody @Valid TopicoForm form, UriComponentsBuilder uriBuilder){
        Topico topico= form.converter(cursoRepository);
        topicoRepository.save(topico);// salva novo topico
        URI uri = uriBuilder.path("/topicos/{id}").buildAndExpand(topico.getId()).toUri(); //  não vou passar o caminho completo, o caminho do servidor. Só vou passar o caminho do recurso.
        return ResponseEntity.created(uri).body(new TopicoDto(topico));
    }
    @GetMapping("/{id}")
    public ResponseEntity<DetalhesDoTopicoDto> detalhar(@PathVariable Long id){
        Optional<Topico> topico = topicoRepository.findById(id);
        if(topico.isPresent()) {
            return ResponseEntity.ok(new DetalhesDoTopicoDto(topico.get()));
        }
        return ResponseEntity.notFound().build();
    }

    @PutMapping("/{id}")
    @Transactional
    public  ResponseEntity<TopicoDto>atualizar(@PathVariable Long id, @RequestBody @Valid AtualizacaoTopicoForm form ){
        Optional<Topico> optional = topicoRepository.findById(id);
        if(optional.isPresent()) {
            Topico topico = form.atualizar(id,topicoRepository);
            return ResponseEntity.ok(new TopicoDto(topico));
        }
        return ResponseEntity.notFound().build();
    }

    @DeleteMapping("/{id}")
    @Transactional
    public ResponseEntity<?> remover(@PathVariable Long id){
        Optional<Topico> optional = topicoRepository.findById(id);
        if(optional.isPresent()) {
            topicoRepository.deleteById(id);
            return ResponseEntity.ok().build();
        }
        return ResponseEntity.notFound().build();
    }
}
/**

package br.com.alura.forum.repository;

import br.com.alura.forum.modelo.Topico;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 *  Pensando nisso, o pessoal do Spring Boot criou uma facilidade. Você não precisa criar uma classe,
 *  e não precisa implementar aqueles métodos que são sempre iguais e repetitivos. Não vamos trabalhar
 *  com o padrão DAO, vamos utilizar outro padrão chamado Repository. No Spring Data, não vamos criar uma classe,
 *  vamos criar uma interface e ela vai herdar de outra interface do Spring Data que já tem alguns métodos prontos
 *  e abstraídos para nós.
 *
 *  temos uma interface e não uma classe, não preciso colocar nenhuma anotação em cima dela.
 *  Normalmente, as classes que são gerenciadas pelo Spring, temos que colocar um @controller, @service,
 *  @Repository, @Component. Esse, por ser interface, não precisa. O Spring já encontra a classe automaticamente.
 */
public interface TopicoRepository extends JpaRepository<Topico, Long> {
    Page<Topico> findByCurso_Nome(String nomeCurso, Pageable paginacao);
}
/**
 * Essa interface, eu preciso herdar de alguma interface do Spring data. O Spring data tem algumas interfaces
 * que você pode utilizar na herança. No nosso caso, vamos herdar de uma interface chamada JpaRepository.
 * Quando você herda dessa interface, percebe que ela tem um generics que você tem que passar dois tipos.
 * O primeiro é a entidade com que o JpaRepository vai trabalhar (no nosso caso é Topico). E o segundo é
 * qual o tipo do atributo do ID, da chave primária dessa entidade. No nosso caso, estamos usando o Long.
 *
 * Na verdade, como estou herdando, toda vez que herdo ganho tudo da interface ou da classe que estou herdando.
 * Essa interface JpaRepository já tem vários métodos comuns. Daí que vem a facilidade. Você não precisa
 * implementar esses métodos, porque eles são comuns neste tipo de classe
 */

package br.com.alura.forum.controller;

import br.com.alura.forum.controller.dto.DetalhesDoTopicoDto; import br.com.alura.forum.controller.dto.TopicoDto; import br.com.alura.forum.controller.form.AtualizacaoTopicoForm; import br.com.alura.forum.controller.form.TopicoForm; import br.com.alura.forum.modelo.Curso; import br.com.alura.forum.modelo.Topico; import br.com.alura.forum.repository.CursoRepository; import br.com.alura.forum.repository.TopicoRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.web.PageableDefault; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid; import java.net.URI; import java.util.Arrays; import java.util.List; import java.util.Optional;

/**

  • O problema é que em todos os métodos a URL vai se repetir. Se um dia eu quiser alterar,
  • vou ter que alterar em todos os métodos. Podemos tirar a anotação @RequestMapping(Value=
  • "/topicos", method = RequestMethod.GET) de cima do método e colocar em cima da classe.
  • Mas aí, na classe, não vou colocar o método, vou colocar só a URL. Então, é como se
  • disséssemos ao Spring: o TopicosController responde às aquisições que começam com "/ *
  • E aí, no método cadastrar eu faço a mesma coisa. Só que aí é POST ao invés de GET, porque estou
  • postando uma informação, fazendo um cadastro. Dessa maneira, não teria mais conflito. O Spring
  • sabe que a URL é a mesma, mas os métodos são diferentes. */

@RestController @RequestMapping("/topicos")//a mesma url vale para o metodo get e para o post public class TopicosController {

@Autowired
private TopicoRepository topicoRepository;
@Autowired
private CursoRepository cursoRepository;


@GetMapping
@Cacheable(value = "listaDeTopicos")
public Page<TopicoDto>lista(@RequestParam(required = false) String nomeCurso,
                       @PageableDefault(sort="id",direction = Sort.Direction.DESC,size=10) Pageable paginacao){


    if(nomeCurso==null){
        Page<Topico> topicos =topicoRepository.findAll(paginacao);
        return TopicoDto.converter(topicos);
    }else{
        Page<Topico> topicos = topicoRepository.findByCurso_Nome(nomeCurso,paginacao);
        return TopicoDto.converter(topicos);
    }
}
//Funcionamento web - informacoes cadastradas pelo usuario sao armazenadas em Json e o spring chama o "JACKSON"
//para converter em TopicForm
@PostMapping
@Transactional
 public ResponseEntity<TopicoDto> cadastrar(@RequestBody @Valid TopicoForm form, UriComponentsBuilder uriBuilder){
    Topico topico= form.converter(cursoRepository);
    topicoRepository.save(topico);// salva novo topico
    URI uri = uriBuilder.path("/topicos/{id}").buildAndExpand(topico.getId()).toUri(); //  não vou passar o caminho completo, o caminho do servidor. Só vou passar o caminho do recurso.
    return ResponseEntity.created(uri).body(new TopicoDto(topico));
}
@GetMapping("/{id}")
public ResponseEntity<DetalhesDoTopicoDto> detalhar(@PathVariable Long id){
    Optional<Topico> topico = topicoRepository.findById(id);
    if(topico.isPresent()) {
        return ResponseEntity.ok(new DetalhesDoTopicoDto(topico.get()));
    }
    return ResponseEntity.notFound().build();
}

@PutMapping("/{id}")
@Transactional
public  ResponseEntity<TopicoDto>atualizar(@PathVariable Long id, @RequestBody @Valid AtualizacaoTopicoForm form ){
    Optional<Topico> optional = topicoRepository.findById(id);
    if(optional.isPresent()) {
        Topico topico = form.atualizar(id,topicoRepository);
        return ResponseEntity.ok(new TopicoDto(topico));
    }
    return ResponseEntity.notFound().build();
}

@DeleteMapping("/{id}")
@Transactional
public ResponseEntity<?> remover(@PathVariable Long id){
    Optional<Topico> optional = topicoRepository.findById(id);
    if(optional.isPresent()) {
        topicoRepository.deleteById(id);
        return ResponseEntity.ok().build();
    }
    return ResponseEntity.notFound().build();
}

}

solução!

Descobri!!! Meu pom estava sem a dependencia do starter data jpa

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>