Solucionado (ver solução)

Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

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>