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

Java RMI传输非序列化Issue类问题求解

解决Jira Issue类无法通过Java RMI传输的问题

问题背景

通过Java RMI传输Jira REST Client API中的com.atlassian.jira.rest.client.api.domain.Issue类时,因该类未实现Serializable接口,抛出以下序列化异常:

java.rmi.UnmarshalException: error unmarshalling return; 
nested exception is: java.io.WriteAbortedException: writing aborted; 
java.io.NotSerializableException: com.atlassian.jira.rest.client.api.domain.Issue

可行解决方案

方法一:自定义可序列化的Issue DTO类

最稳妥的方式是创建包含业务所需字段的自定义DTO类,实现Serializable接口,在服务端将Jira的Issue对象转换为DTO后再通过RMI传输。

1. 定义IssueDto类

import java.io.Serializable;

public class IssueDto implements Serializable {
    private static final long serialVersionUID = 1L;
    
    private String key;
    private String summary;
    private String statusName;
    private String reporterAccountId;

    public IssueDto(String key, String summary, String statusName, String reporterAccountId) {
        this.key = key;
        this.summary = summary;
        this.statusName = statusName;
        this.reporterAccountId = reporterAccountId;
    }

    // 省略getter方法
    public String getKey() { return key; }
    public String getSummary() { return summary; }
    public String getStatusName() { return statusName; }
    public String getReporterAccountId() { return reporterAccountId; }
}

2. 修改服务端接口JiraConnection

import java.util.List;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.concurrent.TimeoutException;

public interface JiraConnection extends Remote {
    // 替换原方法为返回DTO列表
    public List<IssueDto> getIssuesFromJqlSearch(String jqlSearch) throws RemoteException, TimeoutException;
    // 保留其他原有方法...
}

3. 修改服务端实现类JiraServant的对应方法

import java.util.stream.Collectors;

public class JiraServant extends UnicastRemoteObject implements JiraConnection {
    // 原有代码不变...

    @Override
    public List<IssueDto> getIssuesFromJqlSearch(String jqlSearch) throws RemoteException, TimeoutException {
        try {
            final SearchResult searchResult = getJiraRestClient().getSearchClient()
                    .searchJql(jqlSearch)
                    .get(5000, TimeUnit.SECONDS);
            
            // 将Jira Issue转换为自定义DTO
            return searchResult.getIssues().stream()
                    .map(issue -> new IssueDto(
                            issue.getKey(),
                            issue.getSummary(),
                            issue.getStatus().getName(),
                            issue.getReporter() != null ? issue.getReporter().getAccountId() : null
                    ))
                    .collect(Collectors.toList());
        } catch (TimeoutException e) {
            System.err.println("jira rest client timeout from jql search error. cause: " + e.getMessage());
            throw e;
        } catch (Exception e) {
            System.err.println("jira rest client get issue from jql search error. cause: " + e.getMessage());
            return Collections.emptyList();
        }
    }
}

4. 修改客户端代码使用DTO

public class Main {
    public static void main(String[] args) {
        System.out.println("=== === RMI Client === ===");
        try{
            String url = "rmi://localhost:5097/jira-api";
            JiraConnection jiraConnection = (JiraConnection) Naming.lookup(url);
            String jqlSearch = "project = 'SDR' AND assignee = 627cba6c6ba8640069cf1faa AND status IN (Open) ORDER BY created DESC";

            try {
                List<IssueDto> results = jiraConnection.getIssuesFromJqlSearch(jqlSearch);
                
                for(IssueDto issueDto: results){
                    String reporterAccountId = issueDto.getReporterAccountId();
                    System.out.print("Reporter: "+ jiraConnection.getUser(reporterAccountId));
                    System.out.println(", Key: "+issueDto.getKey() + ", Title: "+issueDto.getSummary() + ", Status: " + issueDto.getStatusName());
                }
                System.out.println("Found "+results.size() +" open issues");
            } catch (TimeoutException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }

        }catch(RemoteException | MalformedURLException e){
            System.out.println("Failed to connect to server");
            System.out.println("Error Message : "+e);
        } catch (NotBoundException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

方法二:在服务端直接处理业务逻辑,返回处理结果

如果客户端仅需要展示特定信息,可直接在服务端完成Issue的字段提取与逻辑处理,返回字符串或简单数据结构,避免传输整个对象:

修改服务端接口与实现

// JiraConnection接口新增/替换方法
public interface JiraConnection extends Remote {
    public List<String> getIssueDetailsFromJqlSearch(String jqlSearch) throws RemoteException, TimeoutException;
}

// JiraServant实现
@Override
public List<String> getIssueDetailsFromJqlSearch(String jqlSearch) throws RemoteException, TimeoutException {
    try {
        final SearchResult searchResult = getJiraRestClient().getSearchClient()
                .searchJql(jqlSearch)
                .get(5000, TimeUnit.SECONDS);
        
        return searchResult.getIssues().stream()
                .map(issue -> {
                    String reporter = issue.getReporter() != null ? getUser(issue.getReporter().getAccountId()) : "Unknown";
                    return String.format("Reporter: %s, Key: %s, Title: %s, Status: %s",
                            reporter, issue.getKey(), issue.getSummary(), issue.getStatus().getName());
                })
                .collect(Collectors.toList());
    } catch (Exception e) {
        System.err.println("jira rest client get issue details error. cause: " + e.getMessage());
        return Collections.emptyList();
    }
}

客户端直接打印结果

List<String> issueDetails = jiraConnection.getIssueDetailsFromJqlSearch(jqlSearch);
issueDetails.forEach(System.out::println);

方法三:动态序列化(不推荐)

通过第三方库(如Jackson、XStream)将Issue对象序列化为JSON/XML字符串,传输后再反序列化,但需处理Jira Issue类的复杂依赖与私有字段,稳定性差,不建议用于生产环境。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:30:39