Search code examples
javaspringspring-bootspring-securityspring-data-jpa

Error creating a bean in java spring security, spring boot application


2023-11-09T18:25:27.163+01:00  WARN 14524 --- [           main] 
ConfigServletWebServerApplicationContext : Exception encountered during context initialization - 
cancelling refresh attempt: 
org.springframework.beans.factory.UnsatisfiedDependencyException: 
Error creating bean with name 'authController' defined in file 
[C:\Users\karol\IdeaProjects\demo\target\classes\com\inn\project\controllers\AuthController.class]: 
Unsatisfied dependency expressed through constructor parameter 0: 
Error creating bean with name 'userService' defined in file [C:\Users\karol\IdeaProjects\demo
\target\classes\com\inn\project\services\UserService.class]: 
Unsatisfied dependency expressed through constructor parameter 2: 
No qualifying bean of type 'com.inn.project.mappers.UserMapper' available: 
expected at least 1 bean which qualifies as autowire candidate. 
Dependency annotations: {}

I have this error in my code.

This is my UserController

package com.inn.project.controllers;

import com.inn.project.models.User;
import com.inn.project.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@CrossOrigin
public class UserController {
    @Autowired
    private UserService userService;

    @GetMapping("/users")
    public List<User> getUsers(){
        return userService.getUsers();
    }
    @PostMapping("/users/addnew")
    public void addUser(@RequestBody User user){
        userService.addUser(user);
    }
    @PutMapping("/users/{id}/edit")
    public void updateUser(@PathVariable("id") Long id, @RequestBody User user){
        userService.updateUser(user);
    }
    @DeleteMapping("/users/{id}/delete")
    public void deleteUser(@PathVariable("id") Long id){
        userService.deleteUser(id);
    }
}

This is AuthController

package com.inn.project.controllers;

import com.inn.project.dtos.UserDto;
import com.inn.project.services.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
public class AuthController {
    private final UserService userService;


    @PostMapping("/login")
    public ResponseEntity<UserDto> login(@RequestBody Credentials credentials){
        UserDto user = userService.login(credentials);
        return ResponseEntity.ok(user);
    }
}

This is User model

package com.inn.project.models;

import jakarta.persistence.*;
import lombok.Data;
import lombok.NoArgsConstructor;

@NoArgsConstructor
@Entity
@Data
@Table(name = "User")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "first_name")
    private String firstName;

    @Column(name = "last_name")
    private String lastName;

    @Column(name = "password")
    private String password;

    private String location;
    private String login;

    @Column(name = "notifications")
    private boolean notifications;


}

This is Mapper:

package com.inn.project.mappers;

import com.inn.project.dtos.UserDto;
import com.inn.project.models.User;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring")
public interface UserMapper {
    UserDto toUser(User user);
}

And this is UserDto:

package com.inn.project.dtos;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserDto {
    private Long id;
    private String firstName;
    private String lastName;
    private String login;
    private String password;
}


Here is UserService

package com.inn.project.services;

import com.inn.project.controllers.Credentials;
import com.inn.project.dtos.UserDto;
import com.inn.project.exceptions.AppException;
import com.inn.project.mappers.UserMapper;
import com.inn.project.models.User;
import com.inn.project.repositories.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.nio.CharBuffer;
import java.util.List;

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final UserMapper userMapper;
    public List<User> getUsers(){
        return userRepository.findAll();
    }
    public UserDto login(Credentials credentials){
        User user = userRepository.findByLogin(credentials.login())
                .orElseThrow(()-> new AppException("Uknown user", HttpStatus.NOT_FOUND));
        if (passwordEncoder.matches(CharBuffer.wrap(credentials.password()),
        user.getPassword()))
        {
            return userMapper.toUser(user);
        }
        throw new AppException("Invalid password", HttpStatus.BAD_REQUEST);

    }
    public void addUser(User user){
        userRepository.save(user);
    }
    public void updateUser(User user){
        userRepository.save(user);
    }
    public void deleteUser(Long id){
        userRepository.deleteById(id);
    }
}

<?xml version="1.0" encoding="UTF-8"?>

4.0.0 org.springframework.boot spring-boot-starter-parent 3.1.5 com.inn demo

<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo</description>
<properties>
    <sonar.login>sqp_154364705dbb808ea7aa8df4c3ec133df4a041ba</sonar.login>
    <java.version>17</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.10.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.mapstruct</groupId>
        <artifactId>mapstruct</artifactId>
        <version>1.5.5.Final</version>
    </dependency>
</dependencies>

<build>
    <plugins>


        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.projectlombok</groupId>
                        <artifactId>lombok</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

I tried to find problems like mine, but in the end I gave up, because there was no. I write this code based on this tutorial: https://www.youtube.com/watch?v=YUqi1IjLX8I


Solution

  • Your problem is that you have not actually read the documentation when using mapstruct.

    Map struct is very much like lombok, it generates code during compile time, as in creating a bunch of code for you to map things exactly like lombok generates a bunch of getter and setters, during compile time.

    the example in their github readme clearly explains how you should use it

    ...
    <properties>
        <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
    </properties>
    ...
    <dependencies>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${org.mapstruct.version}</version>
        </dependency>
    </dependencies>
    ...
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${org.mapstruct.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>
    ...
    

    You have not added the annotation processor to the compiler, so there is nothing reading your mapstruct annotations, and generating the code needed so when the server starts it complains that there are things missing.

    Please read the instructions on how to use mapstruct