使用 java RMI 传递复合对象



我需要使用RMI为客户发送药物计划。服务器和客户端位于不同的项目中,两者都定义了以下类(实体和远程接口(:

public class Plan implements Serializable {
private Integer id;
private Date periodStart;
private Date periodEnd;
private Integer patientId;
private Medication medications;
}
public class Medication implements Serializable {
private Integer id;
private String name;
private Integer dosage;
private Integer intakeInterval;
}
public interface PillService extends Remote {
public Plan getPlan(int id) throws RemoteException;
}

上面的代码工作正常,但我需要在Plan中列出药物列表,如下所示:

public class Plan implements Serializable {
...
private List<Medication> medications;
}

如果我使用此Plan类运行,则会出现以下异常:

Client exception: java.rmi.UnmarshalException: error unmarshalling return; nested exception is: 
java.lang.ClassNotFoundException: org.hibernate.collection.internal.PersistentBag (no security manager: RMI class loader disabled)

在此之后,我添加了SecutiryManagerSystem出现错误:

java.security.AccessControlException: access denied ("java.net.SocketPermission" "127.0.0.1:1099" "connect,resolve")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)

因此,它无需List<Medication>即可正常工作Plan.RMI不喜欢复合对象吗?我是否应该定义一种新的远程方法来单独获取药物清单?

问题似乎是List的运行时类型。该类在客户端不可用,因此 RMI 正在尝试从远程代码库下载代码。这已被合理地禁用。

最简单的解决方法是使用众所周知的实现进行List。将列表复制到在Plan中设置的位置或在自定义writeObject方法中。

this.medications = new ArrayList<>(medications);

private void writeObject(
ObjectOutputStream out
) throws IOException {
this.medications = new ArrayList<>(this.medications);
out.defaultWriteObject();
}

看起来你List是一个延迟加载实现,所以这将强制它完全加载。您也许可以简单地使用预先加载。

理想情况下,不要使用 RMI,包括 Java 序列化部分。

最新更新