Spring Boot Sping Boot 2.5.0 Jersey JSON反序列化不使用自定义对象Map器配置

im9ewurl  于 2023-03-02  发布在  Spring
关注(0)|答案(1)|浏览(150)

我正在尝试设置一个KotlinSping Boot 应用程序,该应用程序使用Jersey从服务/存储库层对DropWizard API应用程序进行REST调用。在API层中,控制器使用Spring MVC类和注解。因此,我将Jersey设置为一个过滤器,沿着404传递到Spring MVC,从而使应用程序能够处理这两种类型的请求。
我已经抽象了一个ApiUtils类,其中构造、执行JAX-RS调用并处理响应。这个ApiUtils类是一个@Component,并有一个@Autowired构造函数来初始化它。

public ApiUtils(Client jerseyClient, ObjectMapper mapper, ServiceNameProvider serviceNameProvider) {
    this.client = jerseyClient;
//  this.client = ClientBuilder.newClient();
    this.mapper = mapper;
    this.serviceName = serviceNameProvider.getServiceName();

    //in case a jersey client is inserted with a ClientBuilder.newClient() no object mapper
    //is registered; to avoid fall back to default register the given mapper
    if (this.client != null
        && this.client.getConfiguration() != null
        && !this.client.getConfiguration().isRegistered(JacksonJsonProvider.class)
        && !this.client.getConfiguration().isRegistered(JacksonFeature.class)
    ) {
        this.client.register(new JacksonJsonProvider(this.mapper));
    }
}

现在我发现,即使在Sping Boot 中配置的主自定义对象Map器自动连接到此ApiUtils类中,也不会应用自定义对象Map器配置。即使创建新客户端并注册对象Map器,我也会遇到相同的结果。我打印了APIUtils类中自定义对象Map器的所有设置,它们与配置完全相同。
当我向需要反序列化的类添加Annotations时,它成功了,但是如果不使用定制的objectmapper添加Annotations,它就失败了。
一个很好的例子是DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,它被设置为false,但是当存在未知属性时,反序列化失败。只要我将@JsonIgnoreProperties(ignoreUnknown = true)添加到类本身,它就成功了。
我看到过在Jersey和Jackson的autoconfiguration类中注册自定义对象Map器,我也看到过在ApiUtils类中自动连接自定义对象Map器,但是我得到的错误清楚地表明使用了一个没有聚类的默认对象Map器。
这是我在Sping Boot 中用于自定义对象Map器的当前配置。但是我已经尝试了所有构建器和其他类型的配置,我可以找到搜索正确的设置。
我的自定义对象Map器

@Configuration
@Primary
class MyCustomObjectMapper : ObjectMapper() {

    init {

    val kotlinModule: KotlinModule = KotlinModule.Builder()
        .configure(KotlinFeature.NullIsSameAsDefault, true)
        .configure(KotlinFeature.StrictNullChecks, true)
        .configure(KotlinFeature.NullToEmptyCollection, true)
        .configure(KotlinFeature.NullToEmptyMap, true)
        .configure(KotlinFeature.SingletonSupport, true)
        .build()

    this.registerModules(
        kotlinModule,
        JavaTimeModule(),
        Jdk8Module(),
    )

    ...

    // deserialization configuration
    this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
    ...
   }
}

Jackson配置

@Provider
class JacksonConfig : ContextResolver<ObjectMapper> {

    @Autowired
    private lateinit var objectMapper: MyCustomObjectMapper

    override fun getContext(type: Class<*>?): ObjectMapper {
        return objectMapper
    }
}

球衣配置

@Configuration
@ApplicationPath(JERSEY_API_PATH)
class JerseyConfig : ResourceConfig() {

  init {
        
    register(packages("eu.mypackage.services.web.cg.configuration"));
    register(packages("eu.mypackage.services.web.cg.controller"));
    register(EndpointJerseyLoggingListener(JERSEY_API_PATH));

    //https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/howto-jersey.htmls
    properties = mapOf(
        ServerProperties.RESPONSE_SET_STATUS_OVER_SEND_ERROR to true,
        ServletProperties.FILTER_FORWARD_ON_404 to true
    )

  }
}

我完全没有选择了...是Spring MVC导致了这个问题,尽管我没有在ApiUtils类中使用它?有没有其他方法可以为Jersey客户端使用自定义的对象Map器,然后将其自动连接到外部java ApiUtils类?

snz8szmq

snz8szmq1#

问题似乎是在我的项目中配置的Jersey客户端没有正确设置。

@Provider
class JacksonConfig : ContextResolver<ObjectMapper>

似乎导致我的ApiUtils类自动连接一个没有使用自定义对象Map器的Jersey客户机。
因此,通过使用注解自定义objectmapper类

@Configuration
@Primary

删除

@Provider
class JacksonConfig : ContextResolver<ObjectMapper>

并创建一个JerseyClientConfiguration类:

@Configuration
class JerseyClientConfiguration {

    @Value("\${jerseyClient.timeout}")
    var timeout: Long = 0

    @Value("\${jerseyClient.connectionTimeout}")
    var connectionTimeout: Long = 0

    @Value("\${jerseyClient.threads}")
    var threads = 0

    /**
     * Create a new instance of the JerseyClient and bind it to the Spring context.
     * Needed for ApiUtils
     */
    @Bean
    fun jerseyClient(): Client {

        val connectionManager = PoolingHttpClientConnectionManager()
        connectionManager.maxTotal = threads
        connectionManager.defaultMaxPerRoute = threads

        val client = ClientBuilder.newBuilder()
            .connectTimeout(connectionTimeout, TimeUnit.MILLISECONDS)
            .readTimeout(timeout, TimeUnit.MILLISECONDS)
            .property("jersey.config.client.async.threadPoolSize", threads)
            .build()

            val provider: JacksonJsonProvider = JacksonJaxbJsonProvider(
                ObjectMapper(),
                JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS
            )
        client.register(provider)
        return client
    }
}

我终于让JerseyClient使用了自定义配置。
也许有一个更好的Sping Boot 方法可以让相同的配置工作。如果有,请随时启发我们。

相关问题