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

如何从Xero Java API的getContactsForHttpResponse获取XML响应体?

问题描述

我正在基于Xero Java API开展概念验证测试,希望获取HttpResponse的XML响应体。以下是我的代码(参考自Xero Java自定义连接启动项目),目前API使用自定义类加载Xero的数据,但我想拿到原始XML格式的响应体,尝试过类似contacts.getbody();的方式,请问有没有更优的方法?

import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.api.client.auth.oauth2.ClientCredentialsTokenRequest;
import com.google.api.client.auth.oauth2.RefreshTokenRequest;
import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.auth.oauth2.TokenResponseException;
import com.google.api.client.http.BasicAuthentication;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.xero.api.ApiClient;
import com.xero.api.client.AccountingApi;
import com.xero.api.client.IdentityApi;
import com.xero.models.identity.Connection;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class XeroConnection {
    private static final long serialVersionUID = 1L;
    final String clientId = "Myid";
    final String clientSecret = "MySecret";
    final String TOKEN_SERVER_URL = "https://identity.xero.com/connect/token";
    final NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    final JsonFactory JSON_FACTORY = new JacksonFactory();
    private AccountingApi accountingApi;
    final static Logger logger = LoggerFactory.getLogger(XeroConnection.class);

    private String jwt_token = "";
    private String access_token = "";
    private String refresh_token = "";
    private String expires_in_seconds = "";
    private String xero_tenant_id = "";

public XeroConnection (){
}

public void test() {
    ArrayList<String> scopeList = new ArrayList<String>();
    scopeList.add("accounting.settings");
    scopeList.add("accounting.transactions");
    scopeList.add("accounting.contacts");
    scopeList.add("accounting.journals.read");
    scopeList.add("accounting.reports.read");
    scopeList.add("accounting.attachments");

    try {
        TokenResponse tokenResponse =
        new ClientCredentialsTokenRequest(HTTP_TRANSPORT, JSON_FACTORY,
            new GenericUrl(TOKEN_SERVER_URL))
            .setScopes(scopeList)
            .setClientAuthentication(
            new BasicAuthentication(clientId, clientSecret)).execute();
        System.out.println("Access token: " + tokenResponse.getAccessToken());
        ApiClient defaultIdentityClient = new ApiClient("https://api.xero.com", null, null, null, null);
        IdentityApi idApi = new IdentityApi(defaultIdentityClient);
        List<Connection> connection = idApi.getConnections(tokenResponse.getAccessToken(),null);

        jwt_token = tokenResponse.toPrettyString();
        access_token = tokenResponse.getAccessToken();
        refresh_token = tokenResponse.getRefreshToken();
        expires_in_seconds = tokenResponse.getExpiresInSeconds().toString();
        xero_tenant_id = connection.get(0).getTenantId().toString();

        // Check expiration of token and refresh if necessary
        String accessToken = checkToken(access_token,refresh_token);

        // Init AccountingApi client
        ApiClient defaultClient = new ApiClient();

        // Get Singleton - instance of accounting client
        accountingApi = AccountingApi.getInstance(defaultClient);   


        // Get All Contacts
        HttpResponse contacts = accountingApi.getContactsForHttpResponse(accessToken,xero_tenant_id,null, null, null, null, null, null, null);
        
        //contacts.getbody();



    }catch (Exception e) {
            System.out.println(e.getMessage());
    }

}

public String checkToken(String accessToken, String refreshToken) throws IOException {
    String currToken = null;

    try {
        DecodedJWT jwt = JWT.decode(accessToken);

        if (jwt.getExpiresAt().getTime() > System.currentTimeMillis()) {
            if (logger.isDebugEnabled()) {
                logger.debug(
                        "------------------ Refresh Token : NOT NEEDED - return current token -------------------");
            }
            currToken = accessToken;
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("------------------ Refresh Token : BEGIN -------------------");
            }
            try {
                TokenResponse tokenResponse = new RefreshTokenRequest(new NetHttpTransport(), new JacksonFactory(),
                        new GenericUrl(TOKEN_SERVER_URL), refreshToken)
                        .setClientAuthentication(new BasicAuthentication(this.clientId, this.clientSecret))
                        .execute();
                if (logger.isDebugEnabled()) {
                    logger.debug("------------------ Refresh Token : SUCCESS -------------------");
                }

                // DEMO PURPOSE ONLY - You'll need to implement your own token storage solution
                jwt_token = tokenResponse.toPrettyString();
                access_token = tokenResponse.getAccessToken();
                refresh_token = tokenResponse.getRefreshToken();
                expires_in_seconds = tokenResponse.getExpiresInSeconds().toString();

                currToken = tokenResponse.getAccessToken();
            } catch (TokenResponseException e) {
                if (logger.isDebugEnabled()) {
                    logger.debug("------------------ Refresh Token : EXCEPTION -------------------");
                }
                if (e.getDetails() != null) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Error: " + e.getDetails().getError());
                    }
                    if (e.getDetails().getErrorDescription() != null) {
                        if (logger.isDebugEnabled()) {
                            logger.debug(e.getDetails().getErrorDescription());
                        }
                    }
                    if (e.getDetails().getErrorUri() != null) {

                        if (logger.isDebugEnabled()) {
                            logger.debug(e.getDetails().getErrorUri());
                        }
                    }
                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("------------------ Refresh Token : EXCEPTION -------------------");
                        logger.debug(e.getMessage());
                    }
                }
            }
        }

    } catch (JWTDecodeException exception) {
        if (logger.isDebugEnabled()) {
            logger.debug("------------------ Refresh Token : INVALID TOKEN -------------------");
            logger.debug(exception.getMessage());
        }
    }

    return currToken;
}
}
解决方案

要获取Xero API返回的原始XML响应体,需先配置客户端接受XML格式,再通过输入流读取完整响应内容,具体实现如下:

1. 配置ApiClient接受XML

默认情况下Xero Java SDK优先使用JSON,需手动设置Accept请求头指定XML格式:

// 初始化ApiClient时添加默认头
ApiClient defaultClient = new ApiClient();
defaultClient.addDefaultHeader("Accept", "application/xml");

2. 读取原始XML响应体

通过HttpResponse.getContent()获取输入流,再转换为字符串,这比直接调用getBody()更可靠(getBody()可能已被SDK解析为Java对象):

// 获取Contacts的HttpResponse
HttpResponse contactsResponse = accountingApi.getContactsForHttpResponse(accessToken, xero_tenant_id, null, null, null, null, null, null, null);

// 读取并转换为XML字符串
String xmlResponse = "";
try (BufferedReader reader = new BufferedReader(new InputStreamReader(contactsResponse.getContent()))) {
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
        sb.append(line);
    }
    xmlResponse = sb.toString();
    // 输出或处理XML内容
    System.out.println("原始XML响应:\n" + xmlResponse);
} catch (IOException e) {
    logger.error("读取XML响应失败", e);
}

注意事项

  • 确保你的API权限(scope)包含对应资源的访问权限,否则会返回权限错误的XML
  • 若需同时支持JSON和XML,可根据请求动态切换Accept头
  • 使用try-with-resources语法自动关闭输入流,避免资源泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 02:22:03