Несоответствие типов выводимый тип-KFunction9

#java #spring-boot #kotlin

Вопрос:

Я пытаюсь передать элемент InstaUserDetails в функции карты с помощью ссылки на метод . Я хочу передать весь пользовательский элемент, полученный из базы данных, потому что класс InstaUserDetails расширяет класс пользователя. Но когда я передаю пользовательские данные внутри функции карты, они показывают следующий тип ошибки

 Type mismatch.
Required:
((User!) → TypeVariable(U)!)!
Found:
KFunction9<String, String, String, String, LocalDate, LocalDate, Boolean, Profile, (Mutable)Set<Role!>, InstaUserDetails
 

InstaUserDetails.java

 package com.nilmani.mychat.model;

import org.jetbrains.annotations.NotNull;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.time.LocalDate;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;

public class InstaUserDetails extends User implements UserDetails {
    public InstaUserDetails(@NotNull String id, @NotNull String userName, @NotNull String password, @NotNull String email, @NotNull LocalDate createdAt, @NotNull LocalDate updatedAt, boolean active, @NotNull Profile userProfile, @NotNull Set<Role> role) {
        super(id, userName, password, email, createdAt, updatedAt, active, userProfile, role);
    }

    /**
     * Returns the authorities granted to the user. Cannot return <code>null</code>.
     *
     * @return the authorities, sorted by natural key (never <code>null</code>)
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return getRole()
                .stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" role.getName()))
                .collect(Collectors.toList());
    }

    /**
     * Returns the username used to authenticate the user. Cannot return
     * <code>null</code>.
     *
     * @return the username (never <code>null</code>)
     */
    @Override
    public String getUsername() {
        return "userName";
    }

    /**
     * Indicates whether the user's account has expired. An expired account cannot be
     * authenticated.
     *
     * @return <code>true</code> if the user's account is valid (ie non-expired),
     * <code>false</code> if no longer valid (ie expired)
     */
    @Override
    public boolean isAccountNonExpired() {
        return isAccountNonExpired();
    }

    /**
     * Indicates whether the user is locked or unlocked. A locked user cannot be
     * authenticated.
     *
     * @return <code>true</code> if the user is not locked, <code>false</code> otherwise
     */
    @Override
    public boolean isAccountNonLocked() {
        return isAccountNonLocked();
    }

    /**
     * Indicates whether the user's credentials (password) has expired. Expired
     * credentials prevent authentication.
     *
     * @return <code>true</code> if the user's credentials are valid (ie non-expired),
     * <code>false</code> if no longer valid (ie expired)
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return isCredentialsNonExpired();
    }

    /**
     * Indicates whether the user is enabled or disabled. A disabled user cannot be
     * authenticated.
     *
     * @return <code>true</code> if the user is enabled, <code>false</code> otherwise
     */
    @Override
    public boolean isEnabled() {
        return isEnabled();
    }
}
 

Пользователь.kt

 package com.nilmani.mychat.model

import org.jetbrains.annotations.NotNull
import org.springframework.data.mongodb.core.mapping.Document
import java.time.Instant
import java.time.LocalDate

@Document
open  class User(
    var id:String="",
    var userName:String="",
    var password:String="",
    var email:String="",
    var createdAt:LocalDate=LocalDate.now(),
    var updatedAt:LocalDate= LocalDate.now(),
    var active:Boolean=false,
    @NotNull
    var userProfile:Profile,
    @NotNull
    var role:Set<Role> = HashSet()
)
 

JwtTokenAuthenticationFilter.kt

 package com.nilmani.mychat.config

import com.nilmani.mychat.model.InstaUserDetails
import com.nilmani.mychat.model.Profile
import com.nilmani.mychat.model.Role
import com.nilmani.mychat.service.JwtTokenProvider
import com.nilmani.mychat.service.UserService
import io.jsonwebtoken.Claims
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.web.filter.OncePerRequestFilter
import java.io.IOException
import java.time.LocalDate
import java.util.*
import javax.servlet.FilterChain
import javax.servlet.ServletException
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse


class JwtTokenAuthenticationFilter(jwtConfig: JwtConfig, jetTokenProvider: JwtTokenProvider, userService: UserService) : OncePerRequestFilter() {
    @Autowired
    private lateinit var jwtConfig: JwtConfig
    @Autowired
    private lateinit var jwtTokenProvider: JwtTokenProvider
    @Autowired
    private lateinit var userService: UserService
    /**
     * Same contract as for `doFilter`, but guaranteed to be
     * just invoked once per request within a single request thread.
     * See [.shouldNotFilterAsyncDispatch] for details.
     *
     * Provides HttpServletRequest and HttpServletResponse arguments instead of the
     * default ServletRequest and ServletResponse ones.
     */
    @Throws(IOException::class,ServletException::class)
    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val header:String = request.getHeader(jwtConfig.header)

        if (header == null || !header.startsWith(jwtConfig.prefix)){
            filterChain.doFilter(request,response)
            return
        }
        val token:String = header.replace(jwtConfig.prefix,"")
        if (jwtTokenProvider.validateToken(token)){
            val claims:Claims = jwtTokenProvider.getClaimsFromJWT(token)
            val username:String = claims.subject

            val auth:UsernamePasswordAuthenticationToken =
                userService.findByUserName(username)
                    .map(::InstaUserDetails)
                    .map { userDetails ->
                        val authentication = UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.authorities
                        )
                        authentication.details = WebAuthenticationDetailsSource().buildDetails(request)
                        authentication
                    }
                    .orElse(null)
            SecurityContextHolder.getContext().authentication=auth
        }else{
            SecurityContextHolder.clearContext()
        }

       filterChain.doFilter(request,response)
    }
}
 

Как передать пользовательские данные без каких-либо ошибок внутри
Фильтр проверки подлинности JW.kt
Ошибка отображается в этой конкретной точке

 val auth:UsernamePasswordAuthenticationToken =
                userService.findByUserName(username)
                    .map(::InstaUserDetails)
                    .map { userDetails ->
                        val authentication = UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.authorities
                        
 

До того, как мой класс фильтров будет выглядеть следующим образом

 val username:String = claims.subject

            val auth:UsernamePasswordAuthenticationToken =
                userService.findByUserName(username)
                    .map { id: String, userName: String, password: String, email: String, createdAt: LocalDate, updatedAt: LocalDate, active: Boolean, userProfile: Profile, role: Set<Role> ->
                        InstaUserDetails(
                            id!!,
                            userName!!,
                            password!!,
                            email!!,
                            createdAt!!,
                            updatedAt!!,
                            active,
                            userProfile!!,
                            role!!
                        )
 

Комментарии:

1. Каков тип возвращаемых данных findByUserName() ? Вообще говоря, конструктор вашего InstaUserDetails получает несколько аргументов, но вы пытаетесь вызвать его только с одним аргументом, который является каким-то пользовательским объектом. Вам необходимо создать дополнительный конструктор, который принимает этот однопользовательский объект, или развернуть данные в map() нем .

2. Если я разверну данные на карте() Это показывает ту же ошибку , я уже пробовал этот способ, но я хочу вернуть данные InstaUserDetails, как я могу это сделать

3. Что ты пробовал? Это должно быть что-то вроде: map { InstaUserDetails(...) } и вам нужно указать все 9 параметров, как вы бы создавали InstaUserDetails объект в любом другом месте, за пределами map() .

4. Я расширяю данные в map() следующим образом .map { идентификатор: Строка, Имя пользователя: Строка, пароль: Строка, электронная почта: Строка, Созданное: Локальная дата, обновленное: Локальная дата, активное: Логическое значение, Профиль пользователя: Профиль, роль: Установить<Роль> )

5. Какой тип объектов возвращается findByUserName() ? Это тот же User самый объект, который InstaUserDetails расширяется?