Spring:没有带有预设内容类型“null”的 [class java.util.ArrayList] 转换器

发布于 2025-01-10 15:26:30 字数 9490 浏览 0 评论 0原文

即使似乎已经解决了明显的可能原因(缺少 Survey 类上的公共 getter、缺少依赖项中的 Jackson...),我仍然不断收到此错误

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ArrayList] with preset Content-Type 'null'] with root cause

org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ArrayList] with preset Content-Type 'null'

:控制器无法工作:

@RestController
@RequestMapping("/api")
public class SurveyController {

    @Autowired
    SurveyService surveyService;

    @RequestMapping(value = "/surveys", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody List<Survey> getAllSurveys() {
        List<Survey> surveys = surveyService.findAll();

        return surveys; // <-- ERROR HERE
    }
}

公共 getter 和 setter 已生成:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Survey {
    private String sid;
    private String surveyls_title;
    @Nullable
    private String startdate;
    @Nullable
    private String expires;
    private String active;
}

该服务的工作原理预期返回调查列表

@Service
public class SurveyService implements SurveyServiceInterface{

    @Autowired
    WebClient webClient;

    private final String SESSION_KEY = "***************";

    public List<Survey> findAll() {

        RPCRequest<Object> rpcRequest = RPCRequest.builder()
                .method("list_surveys")
                .id(1)
                .params(new ArrayList<>(){{
                    add(SESSION_KEY);
                }})
                .build();

        RPCResponse<Survey> rpcResponse = webClient.post()
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(rpcRequest))
                .retrieve()
                .bodyToMono(RPCResponse.class)
                .single()
                .block();

        return rpcResponse.getResult();
    }
}
@Configuration
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer{

    @Bean
    public WebClient getWebClient() {
        HttpClient httpClient = HttpClient.create()
                .tcpConfiguration(client ->
                        client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
                                .doOnConnected(conn -> conn
                                        .addHandlerLast(new ReadTimeoutHandler(10))
                                        .addHandlerLast(new WriteTimeoutHandler(10))));

        ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient.wiretap(true));

        return WebClient.builder()
                .baseUrl("https://****.net/***.php/***/remotecontrol")
                .clientConnector(connector)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .exchangeStrategies(ExchangeStrategies.builder().codecs(this::acceptedCodecs).build())
                .build();
    }

    private void acceptedCodecs(ClientCodecConfigurer clientCodecConfigurer) {
        clientCodecConfigurer.customCodecs().register(new Jackson2JsonEncoder(new ObjectMapper(), MediaType.valueOf("text/javascript;charset=UTF-8")));
        clientCodecConfigurer.customCodecs().register(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.valueOf("text/javascript;charset=UTF-8")));
    }
}

POM.xml

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.6</version>
  </parent>

  <properties>
    <java.version>17</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>2.1.210</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

依赖树显示存在 jackson-databind 和 jackson-core

[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ SurveyAPI ---
[INFO] com.**********:SurveyAPI:jar:0.0.1-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.5.6:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.5.6:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:2.5.6:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.5.6:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.5.6:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.6:compile
[INFO] |  |  |  |  +- ch.qos.logback:logback-core:jar:1.2.6:compile
[INFO] |  |  |  |  \- org.slf4j:slf4j-api:jar:1.7.32:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.14.1:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.14.1:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.32:compile
[INFO] |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] |  |  +- org.springframework:spring-core:jar:5.3.12:compile
[INFO] |  |  |  \- org.springframework:spring-jcl:jar:5.3.12:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.28:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.5.6:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.12.5:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.12.5:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.12.5:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.12.5:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.12.5:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.12.5:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.5.6:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.54:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.54:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.54:compile
[INFO] |  +- org.springframework:spring-web:jar:5.3.12:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.3.12:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.3.12:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.3.12:compile
[INFO] |     +- org.springframework:spring-context:jar:5.3.12:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.3.12:compile
[INFO] +- org.springframework.boot:spring-boot-starter-webflux:jar:2.5.6:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.5.6:compile
[INFO] |  |  \- io.projectreactor.netty:reactor-netty-http:jar:1.0.12:compile
[INFO] |  |     +- io.netty:netty-codec-http:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-common:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-buffer:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-transport:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-codec:jar:4.1.69.Final:compile
[INFO] |  |     |  \- io.netty:netty-handler:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-codec-http2:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-resolver-dns:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-resolver:jar:4.1.69.Final:compile
[INFO] |  |     |  \- io.netty:netty-codec-dns:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-resolver-dns-native-macos:jar:osx-x86_64:4.1.69.Final:compile
[INFO] |  |     |  \- io.netty:netty-transport-native-unix-common:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.69.Final:compile
[INFO] |  |     \- io.projectreactor.netty:reactor-netty-core:jar:1.0.12:compile
[INFO] |  |        \- io.netty:netty-handler-proxy:jar:4.1.69.Final:compile
[INFO] |  |           \- io.netty:netty-codec-socks:jar:4.1.69.Final:compile
[INFO] |  \- org.springframework:spring-webflux:jar:5.3.12:compile
[INFO] |     \- io.projectreactor:reactor-core:jar:3.4.11:compile
[INFO] |        \- org.reactivestreams:reactive-streams:jar:1.0.3:compile
[INFO] +- com.h2database:h2:jar:2.1.210:compile
[INFO] \- org.projectlombok:lombok:jar:1.18.22:provided

有人知道我做错了什么吗?谢谢

I keep getting this error even if the obvious possible causes seems to be taken care of (missing public getters on Survey class, missing jackson from dependency...)

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ArrayList] with preset Content-Type 'null'] with root cause

org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.ArrayList] with preset Content-Type 'null'

Controller not working:

@RestController
@RequestMapping("/api")
public class SurveyController {

    @Autowired
    SurveyService surveyService;

    @RequestMapping(value = "/surveys", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public @ResponseBody List<Survey> getAllSurveys() {
        List<Survey> surveys = surveyService.findAll();

        return surveys; // <-- ERROR HERE
    }
}

The public getters and setters are beign generated:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Survey {
    private String sid;
    private String surveyls_title;
    @Nullable
    private String startdate;
    @Nullable
    private String expires;
    private String active;
}

The service works as expected returning the list of Surveys

@Service
public class SurveyService implements SurveyServiceInterface{

    @Autowired
    WebClient webClient;

    private final String SESSION_KEY = "***************";

    public List<Survey> findAll() {

        RPCRequest<Object> rpcRequest = RPCRequest.builder()
                .method("list_surveys")
                .id(1)
                .params(new ArrayList<>(){{
                    add(SESSION_KEY);
                }})
                .build();

        RPCResponse<Survey> rpcResponse = webClient.post()
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.APPLICATION_JSON)
                .body(BodyInserters.fromValue(rpcRequest))
                .retrieve()
                .bodyToMono(RPCResponse.class)
                .single()
                .block();

        return rpcResponse.getResult();
    }
}
@Configuration
@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer{

    @Bean
    public WebClient getWebClient() {
        HttpClient httpClient = HttpClient.create()
                .tcpConfiguration(client ->
                        client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000)
                                .doOnConnected(conn -> conn
                                        .addHandlerLast(new ReadTimeoutHandler(10))
                                        .addHandlerLast(new WriteTimeoutHandler(10))));

        ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient.wiretap(true));

        return WebClient.builder()
                .baseUrl("https://****.net/***.php/***/remotecontrol")
                .clientConnector(connector)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .exchangeStrategies(ExchangeStrategies.builder().codecs(this::acceptedCodecs).build())
                .build();
    }

    private void acceptedCodecs(ClientCodecConfigurer clientCodecConfigurer) {
        clientCodecConfigurer.customCodecs().register(new Jackson2JsonEncoder(new ObjectMapper(), MediaType.valueOf("text/javascript;charset=UTF-8")));
        clientCodecConfigurer.customCodecs().register(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.valueOf("text/javascript;charset=UTF-8")));
    }
}

POM.xml

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.6</version>
  </parent>

  <properties>
    <java.version>17</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <version>2.1.210</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

Dependency tree shows that jackson-databind and jackson-core are present

[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ SurveyAPI ---
[INFO] com.**********:SurveyAPI:jar:0.0.1-SNAPSHOT
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.5.6:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:2.5.6:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:2.5.6:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:2.5.6:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:2.5.6:compile
[INFO] |  |  |  +- ch.qos.logback:logback-classic:jar:1.2.6:compile
[INFO] |  |  |  |  +- ch.qos.logback:logback-core:jar:1.2.6:compile
[INFO] |  |  |  |  \- org.slf4j:slf4j-api:jar:1.7.32:compile
[INFO] |  |  |  +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.14.1:compile
[INFO] |  |  |  |  \- org.apache.logging.log4j:log4j-api:jar:2.14.1:compile
[INFO] |  |  |  \- org.slf4j:jul-to-slf4j:jar:1.7.32:compile
[INFO] |  |  +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] |  |  +- org.springframework:spring-core:jar:5.3.12:compile
[INFO] |  |  |  \- org.springframework:spring-jcl:jar:5.3.12:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.28:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-json:jar:2.5.6:compile
[INFO] |  |  +- com.fasterxml.jackson.core:jackson-databind:jar:2.12.5:compile
[INFO] |  |  |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.12.5:compile
[INFO] |  |  |  \- com.fasterxml.jackson.core:jackson-core:jar:2.12.5:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.12.5:compile
[INFO] |  |  +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.12.5:compile
[INFO] |  |  \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.12.5:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.5.6:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.54:compile
[INFO] |  |  +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.54:compile
[INFO] |  |  \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.54:compile
[INFO] |  +- org.springframework:spring-web:jar:5.3.12:compile
[INFO] |  |  \- org.springframework:spring-beans:jar:5.3.12:compile
[INFO] |  \- org.springframework:spring-webmvc:jar:5.3.12:compile
[INFO] |     +- org.springframework:spring-aop:jar:5.3.12:compile
[INFO] |     +- org.springframework:spring-context:jar:5.3.12:compile
[INFO] |     \- org.springframework:spring-expression:jar:5.3.12:compile
[INFO] +- org.springframework.boot:spring-boot-starter-webflux:jar:2.5.6:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.5.6:compile
[INFO] |  |  \- io.projectreactor.netty:reactor-netty-http:jar:1.0.12:compile
[INFO] |  |     +- io.netty:netty-codec-http:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-common:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-buffer:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-transport:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-codec:jar:4.1.69.Final:compile
[INFO] |  |     |  \- io.netty:netty-handler:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-codec-http2:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-resolver-dns:jar:4.1.69.Final:compile
[INFO] |  |     |  +- io.netty:netty-resolver:jar:4.1.69.Final:compile
[INFO] |  |     |  \- io.netty:netty-codec-dns:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-resolver-dns-native-macos:jar:osx-x86_64:4.1.69.Final:compile
[INFO] |  |     |  \- io.netty:netty-transport-native-unix-common:jar:4.1.69.Final:compile
[INFO] |  |     +- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.69.Final:compile
[INFO] |  |     \- io.projectreactor.netty:reactor-netty-core:jar:1.0.12:compile
[INFO] |  |        \- io.netty:netty-handler-proxy:jar:4.1.69.Final:compile
[INFO] |  |           \- io.netty:netty-codec-socks:jar:4.1.69.Final:compile
[INFO] |  \- org.springframework:spring-webflux:jar:5.3.12:compile
[INFO] |     \- io.projectreactor:reactor-core:jar:3.4.11:compile
[INFO] |        \- org.reactivestreams:reactive-streams:jar:1.0.3:compile
[INFO] +- com.h2database:h2:jar:2.1.210:compile
[INFO] \- org.projectlombok:lombok:jar:1.18.22:provided

Does anybody know what I'm doing wrong? Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

庆幸我还是我 2025-01-17 15:26:30

我自己发现了问题:我试图将 WebFlux 和非响应式 Spring 一起使用。我设法通过将注释应用

@EnableAutoConfiguration(exclude = {WebMvcAutoConfiguration.class })

到主类来做到这一点,这解决了启动期间的异常:

Invalid bean definition with name 'requestMappingHandlerAdapter' defined in class path resource [...]: Cannot register bean definition [...] for bean 'requestMappingHandlerAdapter': There is already [...] bound.

但可能禁用了一些产生我所面临问题的 Jackson 组件。

通过返回 Flux 而不是 List 将 SurveyController 转换为反应式控制器即可解决

Found the problem myself: I was trying to use WebFlux and non-reactive Spring together. I managed to do so by applying the annotation

@EnableAutoConfiguration(exclude = {WebMvcAutoConfiguration.class })

to the main class, which solved the exception during boot:

Invalid bean definition with name 'requestMappingHandlerAdapter' defined in class path resource [...]: Cannot register bean definition [...] for bean 'requestMappingHandlerAdapter': There is already [...] bound.

but probably disable some Jackson component generating the problem I was facing.

Solved by converting the SurveyController into a reactive one by returning Flux<Survey> instead of List<Survey>

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文