Springboot 的 Content-Type xml 和 json 请求和响应负载问题

问题描述 投票:0回答:1

我试图了解如何通过配置/依赖项更改来解决这个特定问题。

Java版本:1.8

Springboot版本:2.7.17

请求和响应模型架构是从 XSD 架构生成的。

我尝试用一个小项目进行调试并寻找一些解决方案

发生了什么:

当我尝试 XML 有效负载时,由于

@XmlElement
名称属性,请求和响应模型符合预期,但是当尝试使用 JSON 有效负载时,它尊重类字段而不是
@XmlElement
名称属性。

寻找一些解决方案来解决这个特定问题,其中我将不被允许更改 XSD 的定义,但愿意通过某种配置更改来更改解析逻辑。

限制:我们的 XSD 文件已维护多年,POJO 类将使用

cxf-codegen-plugin
版本
3.0.3
和目标
wsdl2java
生成。因此我不会获得更改 POJO 模式的许可。礼貌地要求提供向后兼容的解决方案。

这是更容易调试的等效示例项目:

XML 有效负载:

POST http://localhost:9990/api/v1/users/test
Content-Type: application/xml
Accept: application/json

<InputRequest>
    <ACCOUNT_NO>12</ACCOUNT_NO>
    <FLAGS>2</FLAGS>
    <POID>1.0.0</POID>
    <PRODUCTS elem="0">
        <CODE>1400337</CODE>
    </PRODUCTS>
</InputRequest>

JSON 负载:

POST http://localhost:9990/api/v1/users/test
Content-Type: application/json
Accept: application/json

{
  "ACCOUNT_NO": "122",
  "FLAGS": 2,
  "POID": "1.0.0",
  "PRODUCTS": {
    "CODE": "1222",
    "ELEM": 0
  }
}

预期回应:

{
  "ACCOUNT_NO": "122",
  "FLAGS": 2,
  "POID": "1.0.0",
  "PRODUCTS": {
    "CODE": "1222",
    "ELEM": 0
  }
}

现实:

{
  "accountno": null,
  "flags": 0,
  "poid": null,
  "products": []
}

POJO(从 XSD 生成)

package com.example.demo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(
        name = "",
        propOrder = {"accountno", "flags", "poid", "products"}
)
@XmlRootElement(
        name = "InputRequest"
)
public class InputRequest implements Serializable {
    private static final long serialVersionUID = 1L;
    @XmlElement(
            name = "ACCOUNT_NO",
            required = true
    )
    protected String accountno;

    @XmlElement(
            name = "FLAGS"
    )
    protected int flags;
    @XmlElement(
            name = "POID",
            required = true
    )
    protected String poid;
    @XmlElement(
            name = "PRODUCTS",
            required = true
    )
    protected List<PRODUCTS> products;

    public InputRequest() {
    }

    public String getACCOUNTNO() {
        return this.accountno;
    }

    public void setACCOUNTNO(String value) {
        this.accountno = value;
    }


    public int getFLAGS() {
        return this.flags;
    }

    public void setFLAGS(int value) {
        this.flags = value;
    }

    public String getPOID() {
        return this.poid;
    }

    public void setPOID(String value) {
        this.poid = value;
    }

    public List<PRODUCTS> getPRODUCTS() {
        if (this.products == null) {
            this.products = new ArrayList();
        }

        return this.products;
    }

    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(
            name = ""
    )
    public static class PRODUCTS extends CODE implements Serializable {
        private static final long serialVersionUID = 1L;
        @XmlAttribute(
                name = "elem"
        )
        protected String elem;

        public PRODUCTS() {
        }

        public String getElem() {
            return this.elem;
        }

        public void setElem(String value) {
            this.elem = value;
        }
    }
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(
            propOrder = {"code"}
    )
     public static class CODE implements Serializable {
        private static final long serialVersionUID = 1L;
        @XmlElement(
                name = "CODE",
                required = true
        )
        protected String code;

        public CODE() {
        }

        public String getCODE() {
            return this.code;
        }

        public void setCODE(String value) {
            this.code = value;
        }
    }

}

休息控制器:

@RestController
@RequestMapping("/api/v1/users")
public class TestController {

    @ResponseStatus(HttpStatus.CREATED)
    @PostMapping(consumes = {MediaType.APPLICATION_JSON_VALUE,MediaType.APPLICATION_XML_VALUE},value = "/test")
    public InputRequest echoXmlUser(@RequestBody InputRequest payload) throws IOException {
        System.out.println(new ObjectMapper().writeValueAsString(payload));
        return payload;
    }

}

pom.xml(尝试不同的依赖关系)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.7.17</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
       <java.version>8</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-test</artifactId>
          <scope>test</scope>
       </dependency>
<!--       <dependency>-->
<!--          <groupId>com.fasterxml.jackson.dataformat</groupId>-->
<!--          <artifactId>jackson-dataformat-xml</artifactId>-->
<!--          <version>2.4.0</version>-->
<!--       </dependency>-->
       <dependency>
          <groupId>org.glassfish.jaxb</groupId>
          <artifactId>jaxb-runtime</artifactId>
          <version>2.3.8</version>
       </dependency>
    </dependencies>
    <build>
       <plugins>
          <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
             <configuration>
                <image>
                   <builder>paketobuildpacks/builder-jammy-base:latest</builder>
                </image>
             </configuration>
          </plugin>
       </plugins>
    </build>

</project>

我尝试使用

jackson-dataformat-xml
jaxb-runtime
库探索一些选项,并尝试调整配置以使其工作。

我正在寻找一些选项,其中该 POJO 保持不变(由于更改后不同客户端的更广泛影响的限制)并且还通过配置更改/依赖项更改支持 XML 和 JSON 有效负载。我也不想在控制器内部做太多改变,因为如果要做这样的事情,我也需要改变 50 个这样不同的控制器。

java json spring spring-boot spring-mvc
1个回答
1
投票

您将需要使用 JAXB 模块 来允许 Jackson 将 JAXB 注释用于元数据。添加为依赖项后,您需要添加一个

@Bean
方法来公开
JaxbAnnotationModule
,以便 Spring Boot 拾取它并添加到 Jackson。

@Bean
public JaxbAnnotationModule jaxbAnnotationModule() {
  return new JaxbAnnotationModule();
}

依赖性

<dependency>
  <groupId>tools.jackson.module</groupId>
  <artifactId>jackson-module-jaxb-annotations</artifactId>
</dependency>

我怀疑 Spring Boot 会为您管理

jackson-module-jaxb-annotations
的版本(通过包含的
jackson-bom
)。如果没有,您应该能够使用
${jackson.version}
作为
<version>
,因为它将包含用于您的 Spring Boot 版本的 Jackson 版本。

© www.soinside.com 2019 - 2024. All rights reserved.