org.springframework.boot.test.context.assertj.AssertProviderApplicationContextInvocationHandler Maven / Gradle / Ivy
/*
* Copyright 2012-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.test.context.assertj;
import java.io.Closeable;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.function.Supplier;
import org.springframework.context.ApplicationContext;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* {@link InvocationHandler} used by {@link ApplicationContextAssertProvider} generated
* proxies.
*
* @author Phillip Webb
*/
class AssertProviderApplicationContextInvocationHandler implements InvocationHandler {
private final Class applicationContextType;
private final ApplicationContext applicationContext;
private final RuntimeException startupFailure;
AssertProviderApplicationContextInvocationHandler(Class applicationContextType,
Supplier contextSupplier) {
this.applicationContextType = applicationContextType;
Object contextOrStartupFailure = getContextOrStartupFailure(contextSupplier);
if (contextOrStartupFailure instanceof RuntimeException) {
this.applicationContext = null;
this.startupFailure = (RuntimeException) contextOrStartupFailure;
}
else {
this.applicationContext = (ApplicationContext) contextOrStartupFailure;
this.startupFailure = null;
}
}
private Object getContextOrStartupFailure(Supplier contextSupplier) {
try {
return contextSupplier.get();
}
catch (RuntimeException ex) {
return ex;
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (isToString(method)) {
return toString();
}
if (isGetSourceContext(method)) {
return getSourceContext(args);
}
if (isGetStartupFailure(method)) {
return getStartupFailure();
}
if (isAssertThat(method)) {
return getAssertThat(proxy);
}
if (isCloseMethod(method)) {
return invokeClose();
}
return invokeApplicationContextMethod(method, args);
}
private boolean isToString(Method method) {
return ("toString".equals(method.getName()) && method.getParameterCount() == 0);
}
@Override
public String toString() {
if (this.startupFailure != null) {
return "Unstarted application context "
+ this.applicationContextType.getName() + "[startupFailure="
+ this.startupFailure.getClass().getName() + "]";
}
ToStringCreator builder = new ToStringCreator(this.applicationContext)
.append("id", this.applicationContext.getId())
.append("applicationName", this.applicationContext.getApplicationName())
.append("beanDefinitionCount",
this.applicationContext.getBeanDefinitionCount());
return "Started application " + builder;
}
private boolean isGetSourceContext(Method method) {
return "getSourceApplicationContext".equals(method.getName())
&& ((method.getParameterCount() == 0) || Arrays.equals(
new Class[] { Class.class }, method.getParameterTypes()));
}
private Object getSourceContext(Object[] args) {
ApplicationContext context = getStartedApplicationContext();
if (!ObjectUtils.isEmpty(args)) {
Assert.isInstanceOf((Class) args[0], context);
}
return context;
}
private boolean isGetStartupFailure(Method method) {
return ("getStartupFailure".equals(method.getName())
&& method.getParameterCount() == 0);
}
private Object getStartupFailure() {
return this.startupFailure;
}
private boolean isAssertThat(Method method) {
return ("assertThat".equals(method.getName()) && method.getParameterCount() == 0);
}
private Object getAssertThat(Object proxy) {
return new ApplicationContextAssert<>((ApplicationContext) proxy,
this.startupFailure);
}
private boolean isCloseMethod(Method method) {
return ("close".equals(method.getName()) && method.getParameterCount() == 0);
}
private Object invokeClose() throws IOException {
if (this.applicationContext instanceof Closeable) {
((Closeable) this.applicationContext).close();
}
return null;
}
private Object invokeApplicationContextMethod(Method method, Object[] args)
throws Throwable {
try {
return method.invoke(getStartedApplicationContext(), args);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
private ApplicationContext getStartedApplicationContext() {
if (this.startupFailure != null) {
throw new IllegalStateException(toString() + " failed to start",
this.startupFailure);
}
return this.applicationContext;
}
}