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

如何避免Sales Cloud V2 Get操作中的反序列化错误

处理Sales Cloud V2非法URI格式的反序列化问题

我们通过Get操作将Sales Cloud V2系统的数据同步至Java微服务,使用SAP Cloud SDK OpenAPI生成器实现,整体运行正常。Sales Cloud V2中存在Account实体,已基于其OpenAPI定义在Java应用中创建了API客户端及模型,其中Account模型的web属性定义如下:

web string($uri)
maxLength: 1280
minLength: 1
title: Website

但Sales Cloud V2系统中有一个Account的web属性值为带双引号的"www.123.info",属于系统维护错误。执行Get操作获取该Account数据时触发如下异常:

org.springframework.web.client.RestClientException: Error while extracting response for type [class com.sap.mkt.b2e.salescloudv2.model.Accountqueryresponse] and content type [application/json;charset=utf-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `java.net.URI` from String ""www.123.info"": not a valid textual representation, problem: Illegal character in path at index 0: "www.123.info"; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.net.URI` from String ""www.123.info"": not a valid textual representation, problem: Illegal character in path at index 0: "www.123.info"

通过Postman获取数据时,JSON响应中该字段为:

...
   "correspondenceLanguage": "en",
   "eMail": "xy.z@sap.com",
   "web": "\"www.123.info\"",
   "id": "11ed932d-90e9-932e-afdb-81255ba8c000",
   "parentId": "11ed932d-90e9-1dfe-afdb-81255ba8c000",
...

该JSON无法正常解析引发异常,可通过以下几种方式添加校验或过滤逻辑,确保值能正常反序列化:

解决方案

方法1:自定义Jackson反序列化器处理脏数据

创建自定义URI反序列化器,在反序列化阶段自动清理字符串首尾的双引号,再尝试转换为URI:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

public class CleanUriDeserializer extends StdDeserializer<URI> {

    public CleanUriDeserializer() {
        super(URI.class);
    }

    @Override
    public URI deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String value = p.getText().trim();
        // 去除首尾双引号
        if (value.startsWith("\"") && value.endsWith("\"")) {
            value = value.substring(1, value.length() - 1);
        }
        try {
            return new URI(value);
        } catch (URISyntaxException e) {
            // 处理仍不合法的情况,可返回null或抛出自定义异常
            return null;
        }
    }
}

在Account模型的web字段上添加注解,指定使用该反序列化器:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;

public class Accountqueryresponse {
    // 其他字段定义...
    
    @JsonDeserialize(using = CleanUriDeserializer.class)
    private URI web;
    
    // getter和setter方法...
}

方法2:修改OpenAPI生成器配置,生成String类型字段后手动转换

若允许调整模型结构,可修改OpenAPI生成器配置,将web字段生成为String类型,再在业务代码中手动清理并转换为URI:

  1. 在OpenAPI生成器配置文件(如openapi-generator.yml)中添加类型映射:
typeMappings:
  uri: String
  1. 重新生成API客户端及模型,此时web字段为String类型
  2. 在业务代码中处理转换逻辑:
public URI cleanAndConvertToUri(String webStr) {
    if (webStr == null) return null;
    String cleaned = webStr.trim();
    if (cleaned.startsWith("\"") && cleaned.endsWith("\"")) {
        cleaned = cleaned.substring(1, cleaned.length() - 1);
    }
    try {
        return new URI(cleaned);
    } catch (URISyntaxException e) {
        // 根据业务需求处理异常,比如返回null或记录日志
        return null;
    }
}

方法3:添加全局响应拦截器预处理JSON

在Spring的RestTemplate或WebClient中添加拦截器,在反序列化前修改响应体,清理web字段中的非法双引号:
以RestTemplate为例,实现自定义响应处理器:

import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.ResponseErrorHandler;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import org.springframework.http.HttpStatus;

public class CleanWebUriResponseHandler implements ResponseErrorHandler {

    private final ResponseErrorHandler delegate;

    public CleanWebUriResponseHandler(ResponseErrorHandler delegate) {
        this.delegate = delegate;
    }

    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return delegate.hasError(response);
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
        delegate.handleError(response);
    }

    @Override
    public void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
        delegate.handleError(response, statusCode);
    }

    public ClientHttpResponse cleanResponse(ClientHttpResponse response) throws IOException {
        if (HttpStatus.OK.equals(response.getStatusCode())) {
            String body = new BufferedReader(new InputStreamReader(response.getBody(), StandardCharsets.UTF_8))
                    .lines()
                    .reduce("", String::concat);
            // 替换web字段中带嵌套引号的内容
            String cleanedBody = body.replaceAll("\"web\":\"\\\\\"(.*?)\\\\\"\"", "\"web\":\"$1\"");
            // 包装响应体,返回清理后的内容
            return new ClientHttpResponse() {
                @Override
                public HttpStatus getStatusCode() throws IOException {
                    return response.getStatusCode();
                }

                @Override
                public int getRawStatusCode() throws IOException {
                    return response.getRawStatusCode();
                }

                @Override
                public String getStatusText() throws IOException {
                    return response.getStatusText();
                }

                @Override
                public void close() {
                    response.close();
                }

                @Override
                public ByteArrayInputStream getBody() throws IOException {
                    return new ByteArrayInputStream(cleanedBody.getBytes(StandardCharsets.UTF_8));
                }

                @Override
                public org.springframework.http.HttpHeaders getHeaders() {
                    return response.getHeaders();
                }
            };
        }
        return response;
    }
}

配置RestTemplate使用该处理器:

RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new CleanWebUriResponseHandler(restTemplate.getErrorHandler()));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 08:22:02