Fix potential issue when Message is not available but not needed

If an isolated function doesn't have Message in its classpath, we
will never actually need to instantiate that class. This change
makes sure we check first.
This commit is contained in:
Dave Syer
2018-04-25 07:27:33 +01:00
parent 8cf3d7bc5a
commit 59f94c1533
4 changed files with 48 additions and 7 deletions

View File

@@ -90,10 +90,12 @@ public abstract class MessageUtils {
return MessageBuilder.withPayload(message).build();
}
ClassLoader classLoader = ((Isolated) handler).getClassLoader();
Class<?> type = ClassUtils.resolveClassName(Message.class.getName(), classLoader);
Class<?> type = ClassUtils.isPresent(Message.class.getName(), classLoader)
? ClassUtils.resolveClassName(Message.class.getName(), classLoader)
: null;
Object payload;
Map<String, Object> headers;
if (type.isAssignableFrom(message.getClass())) {
if (type != null && type.isAssignableFrom(message.getClass())) {
Method getPayload = ClassUtils.getMethod(type, "getPayload");
Method getHeaders = ClassUtils.getMethod(type, "getHeaders");
payload = ReflectionUtils.invokeMethod(getPayload, message);
@@ -101,7 +103,8 @@ public abstract class MessageUtils {
Map<String, Object> map = (Map<String, Object>) ReflectionUtils
.invokeMethod(getHeaders, message);
headers = map;
} else {
}
else {
payload = message;
headers = Collections.emptyMap();
}

View File

@@ -17,6 +17,7 @@
package org.springframework.cloud.function.stream.function;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
@@ -38,19 +39,40 @@ import reactor.core.publisher.Flux;
*
*/
public class ClassLoaderUtils {
@Test
public void fluxIsShared() {
Class<?> flux = ClassUtils.resolveClassName(Flux.class.getName(), createClassLoader());
Class<?> flux = ClassUtils.resolveClassName(Flux.class.getName(),
createClassLoader());
assertThat(flux).isEqualTo(Flux.class);
}
@Test
public void messageIsNotShared() {
Class<?> flux = ClassUtils.resolveClassName(Message.class.getName(), createClassLoader());
Class<?> flux = ClassUtils.resolveClassName(Message.class.getName(),
createClassLoader());
assertThat(flux).isNotEqualTo(Message.class);
}
@Test(expected = IllegalArgumentException.class)
public void messageIsNotAvailable() {
Class<?> flux = ClassUtils.resolveClassName(Message.class.getName(),
createMinimalClassLoader());
assertThat(flux).isNotEqualTo(Message.class);
}
public static ClassLoader createMinimalClassLoader() {
ClassLoader base = ClassLoaderUtils.class.getClassLoader();
try {
return new URLClassLoader(
new URL[] { new File("target/test-classes").toURI().toURL() },
base.getParent());
}
catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
}
public static ClassLoader createClassLoader() {
URL[] urls = findClassPath();
if (urls.length == 1) {
@@ -171,4 +193,5 @@ public class ClassLoaderUtils {
}
}
}
}

View File

@@ -73,7 +73,18 @@ public class MessageUtilsTests {
Object output = MessageUtils.unpack(function, "foo");
assertThat(output).isInstanceOf(Message.class);
@SuppressWarnings("unchecked")
Message<String> message = (Message<String>)output;
Message<String> message = (Message<String>) output;
assertThat(message.getPayload()).isEqualTo("foo");
}
@Test
public void testUnpackIsolatedMessageNotAvailable() throws Exception {
Object function = create(Uppercase.class,
ClassLoaderUtils.createMinimalClassLoader());
Object output = MessageUtils.unpack(function, "foo");
assertThat(output).isInstanceOf(Message.class);
@SuppressWarnings("unchecked")
Message<String> message = (Message<String>) output;
assertThat(message.getPayload()).isEqualTo("foo");
}
@@ -89,6 +100,10 @@ public class MessageUtilsTests {
}
private Object create(Class<Uppercase> type) {
return create(type, loader);
}
private Object create(Class<Uppercase> type, ClassLoader loader) {
return new IsolatedFunction<>((Function<?, ?>) BeanUtils
.instantiate(ClassUtils.resolveClassName(type.getName(), loader)));
}