diff --git a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiServiceExporter.java b/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiServiceExporter.java index ee59076bc3..6b178e2f63 100644 --- a/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiServiceExporter.java +++ b/spring-context/src/main/java/org/springframework/remoting/rmi/JndiRmiServiceExporter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,8 @@ package org.springframework.remoting.rmi; -import java.rmi.NoSuchObjectException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.Properties; @@ -25,6 +26,8 @@ import javax.naming.NamingException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.jndi.JndiTemplate; +import org.springframework.lang.Nullable; +import org.springframework.util.ReflectionUtils; /** * Service exporter which binds RMI services to JNDI. @@ -66,6 +69,27 @@ import org.springframework.jndi.JndiTemplate; */ public class JndiRmiServiceExporter extends RmiBasedExporter implements InitializingBean, DisposableBean { + @Nullable + private static Method exportObject; + + @Nullable + private static Method unexportObject; + + static { + try { + Class portableRemoteObject = + JndiRmiServiceExporter.class.getClassLoader().loadClass("javax.rmi.PortableRemoteObject"); + exportObject = portableRemoteObject.getMethod("exportObject", Remote.class); + unexportObject = portableRemoteObject.getMethod("unexportObject", Remote.class); + } + catch (Throwable ex) { + // java.corba module not available on JDK 9+ + exportObject = null; + unexportObject = null; + } + } + + private JndiTemplate jndiTemplate = new JndiTemplate(); private String jndiName; @@ -116,6 +140,7 @@ public class JndiRmiServiceExporter extends RmiBasedExporter implements Initiali // Initialize and cache exported object. this.exportedObject = getObjectToExport(); + invokePortableRemoteObject(exportObject); rebind(); } @@ -136,11 +161,31 @@ public class JndiRmiServiceExporter extends RmiBasedExporter implements Initiali * Unbind the RMI service from JNDI on bean factory shutdown. */ @Override - public void destroy() throws NamingException, NoSuchObjectException { + public void destroy() throws NamingException, RemoteException { if (logger.isInfoEnabled()) { logger.info("Unbinding RMI service from JNDI location [" + this.jndiName + "]"); } this.jndiTemplate.unbind(this.jndiName); + invokePortableRemoteObject(unexportObject); + } + + + private void invokePortableRemoteObject(@Nullable Method method) throws RemoteException { + if (method != null) { + try { + method.invoke(null, this.exportedObject); + } + catch (InvocationTargetException ex) { + Throwable targetEx = ex.getTargetException(); + if (targetEx instanceof RemoteException) { + throw (RemoteException) targetEx; + } + ReflectionUtils.rethrowRuntimeException(targetEx); + } + catch (Throwable ex) { + throw new IllegalStateException("PortableRemoteObject invocation failed", ex); + } + } } }