From 08ec3d27359e75cfba66af137702fb5539f28ae0 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 16 Jan 2018 11:09:56 +0100 Subject: [PATCH] Improve class condition check This commit improves a class condition check on the actual implementation rather than the general purpose interface. Closes gh-11608 --- ...baseServiceLocatorApplicationListener.java | 5 +- ...erviceLocatorApplicationListenerTests.java | 62 +++++++++++++++++-- 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java b/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java index 8cfc967d3e..c0cd49d08d 100644 --- a/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java +++ b/spring-boot/src/main/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListener.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-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. @@ -40,7 +40,8 @@ public class LiquibaseServiceLocatorApplicationListener @Override public void onApplicationEvent(ApplicationStartingEvent event) { - if (ClassUtils.isPresent("liquibase.servicelocator.ServiceLocator", null)) { + if (ClassUtils.isPresent("liquibase.servicelocator.CustomResolverServiceLocator", + event.getSpringApplication().getClassLoader())) { new LiquibasePresent().replaceServiceLocator(); } } diff --git a/spring-boot/src/test/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListenerTests.java b/spring-boot/src/test/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListenerTests.java index 861f953e81..2d3eb5bfc7 100644 --- a/spring-boot/src/test/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListenerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/liquibase/LiquibaseServiceLocatorApplicationListenerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-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. @@ -17,7 +17,13 @@ package org.springframework.boot.liquibase; import java.lang.reflect.Field; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Arrays; +import java.util.List; +import liquibase.servicelocator.CustomResolverServiceLocator; +import liquibase.servicelocator.DefaultPackageScanClassResolver; import liquibase.servicelocator.ServiceLocator; import org.junit.After; import org.junit.Test; @@ -25,6 +31,7 @@ import org.junit.Test; import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.DefaultResourceLoader; import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -33,6 +40,7 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link LiquibaseServiceLocatorApplicationListener}. * * @author Phillip Webb + * @author Stephane Nicoll */ public class LiquibaseServiceLocatorApplicationListenerTests { @@ -46,15 +54,33 @@ public class LiquibaseServiceLocatorApplicationListenerTests { } @Test - public void replacesServiceLocator() throws Exception { + public void replacesServiceLocator() throws IllegalAccessException { SpringApplication application = new SpringApplication(Conf.class); application.setWebEnvironment(false); this.context = application.run(); + Object resolver = getServiceLocator(); + assertThat(resolver).isInstanceOf(SpringPackageScanClassResolver.class); + } + + @Test + public void replaceServiceLocatorBacksOffIfNotPresent() + throws IllegalAccessException { + SpringApplication application = new SpringApplication(Conf.class); + application.setWebEnvironment(false); + DefaultResourceLoader resourceLoader = new DefaultResourceLoader(); + resourceLoader.setClassLoader(new ClassHidingClassLoader( + CustomResolverServiceLocator.class)); + application.setResourceLoader(resourceLoader); + this.context = application.run(); + Object resolver = getServiceLocator(); + assertThat(resolver).isInstanceOf(DefaultPackageScanClassResolver.class); + } + + private Object getServiceLocator() throws IllegalAccessException { ServiceLocator instance = ServiceLocator.getInstance(); Field field = ReflectionUtils.findField(ServiceLocator.class, "classResolver"); field.setAccessible(true); - Object resolver = field.get(instance); - assertThat(resolver).isInstanceOf(SpringPackageScanClassResolver.class); + return field.get(instance); } @Configuration @@ -62,4 +88,32 @@ public class LiquibaseServiceLocatorApplicationListenerTests { } + private final class ClassHidingClassLoader extends URLClassLoader { + + private final List> hiddenClasses; + + private ClassHidingClassLoader(Class... hiddenClasses) { + super(new URL[0], LiquibaseServiceLocatorApplicationListenerTests.class.getClassLoader()); + this.hiddenClasses = Arrays.asList(hiddenClasses); + } + + @Override + public Class loadClass(String name) throws ClassNotFoundException { + if (isHidden(name)) { + throw new ClassNotFoundException(); + } + return super.loadClass(name); + } + + private boolean isHidden(String name) { + for (Class hiddenClass : this.hiddenClasses) { + if (hiddenClass.getName().equals(name)) { + return true; + } + } + return false; + } + + } + }