You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jersey 2.32 RESTful映射遇空对象或MismatchedInputException问题

问题:VueJS表单JSON数据无法被Jersey 2.32正确解析映射

场景概述

前端通过VueJS表单构建JSON数据,后端使用Jersey 2.32接收并尝试映射解析,但出现参数为null或反序列化异常的问题,需要正确获取数据用于文件上传模块。

前端发送的JSON结构

{"objetDesLiensDuTheme": {"id": 7195,"formalisation": {"selectTitreFichier": "fiche de formalisation","inputTitreFichier": "fiche de formalisation titre fichier","inputFichier": {},},"modop": {"selectTitreFichier": "fiche méthodologique","inputTitreFichier": "fiche méthodologique titre fichier","inputFichier": {},},}}

注:上述为字符串化后的结构,实际inputFichier是浏览器File对象,console.log输出:

inputFichier: File { name: "Fichier formalisation.txt", lastModified: 1690373320586, size: 0, type: "text/plain", webkitRelativePath: ""}

后端代码实现

REST控制器方法

@POST
@Path("/create")
@Consumes(MediaType.APPLICATION_JSON)
public Response createLien(@BeanParam LiensDTO objetDesLiensDuTheme)
{
    Response response;
    //TODO
    System.out.println(objetDesLiensDuTheme);

    response = Response.status(Status.CREATED).build();
    return response;
}

控制台输出显示参数为null:

LiensDTO [objetDesLiensDuTheme=null]

DTO类定义

LiensDTO.java

public class LiensDTO implements Serializable
{
    private static final long serialVersionUID = -5717326975468155988L;

    public LiensDTO()
    {
        super();
    }

    @FormParam("objetDesLiensDuTheme")
    // @JsonProperty("objetDesLiensDuTheme")
    private DocLienDTO objetDesLiensDuTheme;

    @Override
    public String toString()
    {
        return "LiensDTO [objetDesLiensDuTheme=" + objetDesLiensDuTheme + "]";
    }
    // 省略getter/setter
}

DocLienDTO.java

public class DocLienDTO implements Serializable
{
    private static final long serialVersionUID = -493282593738066056L;

    private int id;

    private DocumentDTO formalisation;

    private DocumentDTO modop;
    // 省略getter/setter
}

DocumentDTO.java

public class DocumentDTO implements Serializable
{
  private static final long serialVersionUID = -6698584238714969958L;

  private String selectTitreFichier;

  private String inputTitreFichier;

  private File inputFichier;
  // 省略getter/setter
}

额外异常信息

移除@BeanParam或改用@RequestBody时,抛出反序列化异常:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of api.bean.LiensDTO out of START_ARRAY token at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 1].

实际发送的JSON并非数组结构,也曾尝试用@JsonProperty("objetDesLiensDuTheme")替换@FormParam,问题未解决。


解决方案

1. 修正DTO的JSON映射逻辑

当前JSON根节点是objetDesLiensDuTheme,但LiensDTO将其作为内部属性,导致Jackson无法正确映射,可通过两种方式调整:

  • 方式一:简化DTO结构
    直接将DocLienDTO作为请求参数,因为JSON的核心内容就是DocLienDTO的结构,外层包装objetDesLiensDuTheme属于冗余层级。修改控制器方法:

    @POST
    @Path("/create")
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createLien(DocLienDTO objetDesLiensDuTheme) {
        System.out.println(objetDesLiensDuTheme);
        return Response.status(Status.CREATED).build();
    }
    

    同时可删除LiensDTO,或根据业务需求保留。

  • 方式二:保留LiensDTO并开启根节点解析
    移除@FormParam(该注解用于表单参数,不适用JSON场景),改用@JsonProperty,同时配置Jackson支持根节点映射:

    public class LiensDTO implements Serializable {
        // ...
        @JsonProperty("objetDesLiensDuTheme")
        private DocLienDTO objetDesLiensDuTheme;
        // ...
    }
    

    添加Jersey的Jackson配置类,启用根节点解析特性:

    @Provider
    public class JacksonConfig implements ContextResolver<ObjectMapper> {
        private final ObjectMapper mapper;
    
        public JacksonConfig() {
            mapper = new ObjectMapper();
            mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
            mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
        }
    
        @Override
        public ObjectMapper getContext(Class<?> type) {
            return mapper;
        }
    }
    

2. 解决File对象的序列化问题

浏览器File对象无法直接序列化为JSON,从字符串化的JSON可见inputFichier被转为空对象{},需调整前端提交方式:

  • 改用multipart/form-data格式提交,Vue中使用FormData构建请求:
    const formData = new FormData();
    formData.append('id', 7195);
    formData.append('formalisation.selectTitreFichier', 'fiche de formalisation');
    formData.append('formalisation.inputTitreFichier', 'fiche de formalisation titre fichier');
    formData.append('formalisation.inputFichier', this.form.inputFichier);
    // 同理添加modop相关字段
    axios.post('/create', formData);
    
  • 后端调整控制器与DTO:
    @POST
    @Path("/create")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public Response createLien(@BeanParam DocLienDTO docLienDTO) {
        // 通过FormDataContentDisposition获取文件名等信息
        // docLienDTO.getFormalisation().getFileDisposition().getFileName()
        return Response.status(Status.CREATED).build();
    }
    
    修改DocumentDTO的文件相关字段:
    public class DocumentDTO implements Serializable {
        // ...
        @FormDataParam("inputFichier")
        private InputStream inputFichier;
        @FormDataParam("inputFichier")
        private FormDataContentDisposition fileDisposition;
        // ...
    }
    
    注意:需确保Jersey添加了jersey-media-multipart依赖,支持表单文件上传。

3. 排查"START_ARRAY"异常

虽然你声明发送的不是数组,但异常提示JSON以数组开头,建议通过浏览器开发者工具的Network面板,查看请求的实际Payload内容,确认是否前端代码误将数据包裹为数组(比如JSON.stringify([data]))。

内容的提问来源于stack exchange,提问作者LBS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 12:22:03