Resteasy javax — Как сопоставить тип содержимого * / * с приложением / json на стороне сервера?

#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:

Согласно документации, вы должны иметь возможность получить тело запроса в виде строкового параметра и впоследствии вручную преобразовать его в желаемую форму объекта.