javaspring-bootjavabeansdtomapstruct

SpringBoot - Bean could not be found


I get this error when I run my Spring Boot application:

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.

2024-05-11T14:59:30.328+04:00 ERROR 12628 --- [Assignment-3] [ main] o.s.b.d.LoggingFailureAnalysisReporter :

***************************

APPLICATION FAILED TO START

***************************

Description:

Parameter 1 of constructor in az.edu.ada.wm2.Assignment3.service.impl.BookServiceImpl required a bean of type 'az.edu.ada.wm2.Assignment3.mapper.BookMapper' that could not be found.

Here are my source files:

Book.java

package az.edu.ada.wm2.Assignment3.model.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import jakarta.persistence.*;

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;

    private String author;

    private String description;

    private String publishYear;
}

BookDto.java

package az.edu.ada.wm2.Assignment3.model.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class BookDto {

    private Long id;

    @NotBlank(message = "Title is required")
    @Size(max = 100, message = "Title must be less than 100 characters")
    private String title;

    @NotBlank(message = "Author is required")
    @Size(max = 50, message = "Author must be less than 50 characters")
    private String author;

    @NotBlank(message = "Description is required")
    @Size(max = 200, message = "Description must be less than 200 characters")
    private String description;
}

BookServiceImpl.java

package az.edu.ada.wm2.Assignment3.service.impl;

import az.edu.ada.wm2.Assignment3.mapper.BookMapper;
import az.edu.ada.wm2.Assignment3.model.dto.BookDto;
import az.edu.ada.wm2.Assignment3.model.entity.Book;
import az.edu.ada.wm2.Assignment3.repository.BookRepository;
import az.edu.ada.wm2.Assignment3.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class BookServiceImpl implements BookService {

    private final BookRepository bookRepository;
    private final BookMapper bookMapper;

    @Autowired
    public BookServiceImpl(BookRepository bookRepository, BookMapper bookMapper){
        this.bookRepository=bookRepository;
        this.bookMapper = bookMapper;
    }


    @Override
    public List<BookDto> getAllBooks() {
        return bookRepository.findAll().stream()
                .map(bookMapper::bookToBookDto)
                .collect(Collectors.toList());
    }

    @Override
    public BookDto getBookById(Long id) {
        return bookMapper.bookToBookDto(bookRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Book not found")));
    }


    @Override
    public BookDto createBook(BookDto bookDTO) {
        Book book = bookMapper.bookDtoToBook(bookDTO);
        return bookMapper.bookToBookDto(bookRepository.save(book));
    }

    @Override
    public BookDto updateBook(Long id, BookDto bookDTO) {
        Book existingBook = bookRepository.findById(id)
                .orElseThrow(() -> new RuntimeException("Book not found"));

        existingBook.setTitle(bookDTO.getTitle());
        existingBook.setAuthor(bookDTO.getAuthor());
        existingBook.setDescription(bookDTO.getDescription());

        return bookMapper.bookToBookDto(bookRepository.save(existingBook));
    }

    @Override
    public void deleteBook(Long id) {
        bookRepository.deleteById(id);
    }
}

BookController.java

package az.edu.ada.wm2.Assignment3.controller;

import az.edu.ada.wm2.Assignment3.model.dto.BookDto;
import az.edu.ada.wm2.Assignment3.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.List;

@RestController
@RequestMapping("/books")
public class BookController {

    private final BookService bookService;

    @Autowired
    public BookController(BookService bookService) {
        this.bookService = bookService;
    }

    @GetMapping
    public ResponseEntity<List<BookDto>> getAllBooks() {
        List<BookDto> books = bookService.getAllBooks();
        return ResponseEntity.ok(books);
    }

    @GetMapping("/{id}")
    public ResponseEntity<BookDto> getBookById(@PathVariable Long id) {
        BookDto book = bookService.getBookById(id);
        return ResponseEntity.ok(book);
    }

    @PostMapping
    public ResponseEntity<BookDto> createBook(@Valid @RequestBody BookDto bookDTO) {
        BookDto createdBook = bookService.createBook(bookDTO);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdBook);
    }

    @PutMapping("/{id}")
    public ResponseEntity<BookDto> updateBook(@PathVariable Long id, @Valid @RequestBody BookDto bookDTO) {
        BookDto updatedBook = bookService.updateBook(id, bookDTO);
        return ResponseEntity.ok(updatedBook);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteBook(@PathVariable Long id) {
        bookService.deleteBook(id);
        return ResponseEntity.noContent().build();
    }
}

build.gradle

plugins {
   id 'java'
   id 'org.springframework.boot' version '3.2.5'
   id 'io.spring.dependency-management' version '1.1.4'
}

group = 'az.edu.ada.wm2'
version = '0.0.1-SNAPSHOT'

java {
   sourceCompatibility = '17'
}

configurations {
   compileOnly {
      extendsFrom annotationProcessor
   }
}

repositories {
   mavenCentral()
}

dependencies {
   compileOnly 'org.projectlombok:lombok'
   annotationProcessor 'org.projectlombok:lombok'
   testImplementation 'org.springframework.boot:spring-boot-starter-test'
   implementation 'org.springframework.boot:spring-boot-starter-validation'

   implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
   implementation 'org.springframework.boot:spring-boot-starter-web'
   compileOnly 'org.projectlombok:lombok'
   runtimeOnly 'com.h2database:h2'
   annotationProcessor 'org.projectlombok:lombok'
   implementation 'org.mapstruct:mapstruct:1.5.5.Final'
   annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
   testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
   useJUnitPlatform()
}

I tried using lombok for service class as suggested in most online solutions, however, that didn't help either. Could you please help me to find and fix the issue?


Solution

  • An error a bean of type 'az.edu.ada.wm2.Assignment3.mapper.BookMapper' that could not be found means there is no such been known to Spring, that is no such bean in Spring context. There are many possible reasons of that, but in your case it is about BookMapper generated by mapstruct. You did not supply BookMapper code, but I suppose you missed annotation @Mapper(componentModel = "spring") which makes mapper impl class to be a spring bean. See an example at https://www.baeldung.com/mapstruct