【问题标题】:Name expected in an import annotation in KotlinKotlin 的导入注释中预期的名称
【发布时间】:2019-11-24 01:10:46
【问题描述】:

我有一个用 Kotlin 实现的 Spring Boot App (2.1.6)。是一个希望拥有 oAuth 2 和 Keycloak 的 Rest api。 我在 Java 中有这段代码可以编译:

package com.talleres.paco.mako.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

@Configuration
@EnableWebSecurity
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ConditionalOnProperty(prefix = "rest.security", value = "enabled", havingValue = "true")
@Import({SecurityProperties.class})
public class SecurityConfigurer extends ResourceServerConfigurerAdapter {

  @Autowired
  private ResourceServerProperties resourceServerProperties;

  @Autowired
  private SecurityProperties securityProperties;

  @Override
  public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    resources.resourceId(resourceServerProperties.getResourceId());
  }


  @Override
  public void configure(final HttpSecurity http) throws Exception {

    http.cors()
        .configurationSource(corsConfigurationSource())
        .and()
        .headers()
        .frameOptions()
        .disable()
        .and()
        .csrf()
        .disable()
        .authorizeRequests()
        .antMatchers(securityProperties.getApiMatcher())
        .authenticated();

  }

  @Bean
  public CorsConfigurationSource corsConfigurationSource() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    if (null != securityProperties.getCorsConfiguration()) {
      source.registerCorsConfiguration("/**", securityProperties.getCorsConfiguration());
    }
    return source;
  }

  @Bean
  public JwtAccessTokenCustomizer jwtAccessTokenCustomizer(ObjectMapper mapper) {
    return new JwtAccessTokenCustomizer(mapper);
  }

  @Bean
  public OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails details) {
    OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(details);

    //Prepare by getting access token once
    oAuth2RestTemplate.getAccessToken();
    return oAuth2RestTemplate;
  }
}

当我转换到 Kotlin 时,我得到一个语法错误:

package com.talleres.paco.mako.config.security

import com.fasterxml.jackson.databind.ObjectMapper
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.oauth2.client.OAuth2RestTemplate
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer
import org.springframework.web.cors.CorsConfigurationSource
import org.springframework.web.cors.UrlBasedCorsConfigurationSource

@Configuration
@EnableWebSecurity
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ConditionalOnProperty(prefix = "rest.security", value = ["enabled"], havingValue = "true")
@Import({SecurityProperties.class})
class SecurityConfigurer : ResourceServerConfigurerAdapter() {
    @Autowired
    private val resourceServerProperties: ResourceServerProperties? = null
    @Autowired
    private val securityProperties: SecurityProperties? = null

    @Throws(Exception::class)
    override fun configure(resources: ResourceServerSecurityConfigurer) {
        resources.resourceId(resourceServerProperties!!.resourceId)
    }

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http.cors()
                .configurationSource(corsConfigurationSource())
                .and()
                .headers()
                .frameOptions()
                .disable()
                .and()
                .csrf()
                .disable()
                .authorizeRequests()
                .antMatchers(securityProperties!!.apiMatcher)
                .authenticated()
    }

    @Bean
    fun corsConfigurationSource(): CorsConfigurationSource {
        val source = UrlBasedCorsConfigurationSource()
        if (securityProperties?.corsConfiguration != null) {
            source.registerCorsConfiguration("/**", securityProperties.corsConfiguration);
        }
        return source
    }

    @Bean
    fun jwtAccessTokenCustomizer(mapper: ObjectMapper): JwtAccessTokenCustomizer {
        return JwtAccessTokenCustomizer(mapper)
    }

    @Bean
    fun oauth2RestTemplate(details: OAuth2ProtectedResourceDetails): OAuth2RestTemplate {
        val oAuth2RestTemplate = OAuth2RestTemplate(details)
        oAuth2RestTemplate.accessToken
        return oAuth2RestTemplate
    }
}

错误与注解导入一致:

@Import({SecurityProperties.class})

我使用 IntelliJ CE 将代码从 Java 转换为 Kotlin。消息是:

> Task :compileKotlin
e: D:\Workspaces\CleanArchitecture\mako\src\main\customized\kotlin\com\talleres\paco\mako\config\security\SecurityConfigurer.kt: (26, 34): Name expected

提前致谢。

【问题讨论】:

    标签: spring-boot kotlin compiler-errors annotations


    【解决方案1】:

    我猜想将 Java 代码转换为 Kotlin 的工具并不总是有效。在这种情况下,@Import 是在 Java 中定义的,它需要一个类数组,您可以通过传递 vararg KClass 在 Kotlin 中使用它(实际上这仅适用于注解的 value 字段,否则您需要传递适当的数组。更多信息here)。

    也就是说,您需要将您的代码更改为:@Import(SecurityProperties::class)

    编辑:这个问题似乎在几年前被报告并修复:KT-10545。我还尝试在我的机器上将您的 Java 代码转换为 Kotlin(使用 Kotlin 1.3.41),并且正确生成了 @Import 语句。

    不过,发生了一些有趣的事情。 @ConditionalOnProperty 行已转换为:

    @ConditionalOnProperty(prefix = "rest.security", value = "enabled", havingValue = "true")
    

    它不会编译为“禁止以命名形式将单个元素分配给可变参数”。我很想知道这是否是一种回归,因为它在您的 sn-p 中看起来是正确的。

    【讨论】:

    • 谢谢,您的建议已解决问题。但现在我在想,如果我删除该行,我也可以解决问题。我不明白为什么我们需要导入带有注释的类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    • 2018-12-18
    • 1970-01-01
    • 2018-06-26
    • 2021-12-18
    • 2019-01-16
    • 1970-01-01
    相关资源
    最近更新 更多