#java #json #wildfly #resteasy #content-type
#java #json #wildfly #resteasy #тип содержимого
Вопрос:
Проблема: я не могу получить тип содержимого */*
в клиентском сообщении для сопоставления с application/json
на стороне сервера путем изменения кода сервера, а не кода клиента. (Слишком много развернутых клиентов для выполнения последнего)
На WildFly 10 все работает как есть (с */*
), но на WildFly 14/18 это приводит к сбою с
RESTEASY002010: Failed to execute: javax.ws.rs.NotSupportedException: RESTEASY003200: Could not find message body reader for type: class xxxx of content type: */* at org.jboss.resteasy.resteasy-
jaxrs@3.9.1.Final//org.jboss.resteasy.core.interception.ServerReaderInterceptorContext.throwReaderNotFound
Все вышеперечисленное находится на Java 8. Приведенный ниже код показывает изменение на стороне клиента, которое позволило бы заставить WF14 работать без изменений на стороне сервера:
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "*/*"); // works for WF10, not WF14
// conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); // works for all
Применимый код на стороне сервера выглядит следующим образом:
@POST
@Path("fileDownload")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_OCTET_STREAM)
// Consume options tried that still failed:
// @Consumes({ MediaType.APPLICATION_JSON, MediaType.WILDCARD, MediaType.APPLICATION_OCTET_STREAM, "*/*", "*/*rn", "*/*; charset=UTF-8" } )
public Response fileDownload(@HeaderParam("Range") String range, FileDownloadRequest fileDwnReq) throws IOException { ... }
Все мои поисковые запросы в Сети указывают на изменения на стороне клиента (которые будут работать), но мы должны изменить серверную часть или остаться на WF10. Я также пытался настроить поведение кодировки или сопоставить тип носителя в web.xml но это не имело никакого значения. Например:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>MyRestServices</display-name>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<!--
To specify the previous behavior, in which UTF-8 was used for text media types, but
the explicit charset was not appended, the context parameter "resteasy.add.charset" may be
set to "false". It defaults to "true".
See https://docs.jboss.org/resteasy/docs/3.1.2.Final/userguide/html_single/index.html
This did not work.
-->
<!-- <context-param> -->
<!-- <param-name>resteasy.add.charset</param-name> -->
<!-- <param-value>false</param-value> -->
<!-- </context-param> -->
<context-param>
<param-name>resteasy.media.type.mappings</param-name>
<param-value>*/* : application/json</param-value>
<!-- <param-value>html : text/html, json : application/json, xml : application/xml</param-value> -->
</context-param>
Я в тупике. Любые предложения / указатели будут оценены.
Редактировать: Ниже приведен дамп неудачного http-запроса:
URI=/xxx/fileDownload
characterEncoding=null
contentLength=94
contentType=[*/*]
header=Accept=text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
header=Connection=keep-alive
header=Content-Type=*/*
header=Content-Length=94
header=User-Agent=Java/1.8.0_152
header=Host=127.0.0.1:8014
locale=[]
method=POST
protocol=HTTP/1.1
queryString=
remoteAddr=/127.0.0.1:59867
remoteHost=127.0.0.1
scheme=http
host=127.0.0.1:8014
serverPort=8014
isSecure=false
--------------------------RESPONSE--------------------------
contentLength=0
contentType=null
header=Connection=keep-alive
header=Content-Length=0
header=Date=Thu, 20 Aug 2020 13:36:44 GMT
status=415
Ответ №1:
Я нашел способ, добавив ContainerRequestFilter, который изменяет заголовок перед сопоставлением. Приведенный ниже трюк удался:
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.container.PreMatching;
@Provider
@PreMatching
// Mapp */* to JSON for /filedownload
public final class ContentFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext ctx) throws IOException {
UriInfo uri = ctx.getUriInfo();
if ((uri != null) amp;amp; uri.getPath().toLowerCase().contains("filedownload")) {
String ctp = ctx.getHeaderString("Content-Type");
if ("*/*".equals(ctp))
ctx.getHeaders().putSingle("Content-Type", "application/json; charset=UTF-8");
}
}
}
Мне также пришлось добавить следующее в мой web.xml
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>xxx.yyy.ContentFilter</param-value>
</context-param>
Ответ №2:
Использование подстановочных знаков в «Тип содержимого» на стороне клиента не имеет смысла.
Клиент может принимать ответы сервера в нескольких форматах (используя заголовок «Accept»)
Сервер может принимать (использовать) несколько носителей, но клиент должен знать, какие данные он эффективно отправляет. Если вы не сообщаете серверу, что вы отправляете в теле http, сервер не может (всегда) угадать это.
Комментарии:
1. Я согласен, что это не имеет смысла; однако это то, что уже есть в поле, и я должен найти способ заставить его продолжать работать на WF18, пока мы не сможем исправить клиентов.
Ответ №3:
Согласно документации, вы должны иметь возможность получить тело запроса в виде строкового параметра и впоследствии вручную преобразовать его в желаемую форму объекта.