Remove ApplicationInfo

Rework commit 4a69755b to remove the need for the ApplicationInfo class.
The updated code now uses the auto-configuration class to compute a
default persistence unit root location

Closes gh-6635
This commit is contained in:
Phillip Webb 2016-08-29 22:53:15 +01:00 committed by Stephane Nicoll
parent b488a3d9a3
commit 2a22a7af12
8 changed files with 52 additions and 139 deletions

View File

@ -16,18 +16,21 @@
package org.springframework.boot.autoconfigure.orm.jpa;
import java.net.URL;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.ApplicationInfo;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@ -50,6 +53,7 @@ import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.ResourceUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@ -65,6 +69,8 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
@Import(DataSourceInitializedPublisher.Registrar.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware {
private final Log logger = LogFactory.getLog(getClass());
private final DataSource dataSource;
private final JpaProperties properties;
@ -104,11 +110,9 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
ObjectProvider<PersistenceUnitManager> persistenceUnitManagerProvider) {
EntityManagerFactoryBuilder builder = new EntityManagerFactoryBuilder(
jpaVendorAdapter, this.properties.getProperties(),
persistenceUnitManagerProvider.getIfAvailable());
persistenceUnitManagerProvider.getIfAvailable(),
determinePersistenceUnitRootLocation());
builder.setCallback(getVendorCallback());
if (this.beanFactory.containsBean("springApplicationInfo")) {
builder.setApplicationInfo(this.beanFactory.getBean(ApplicationInfo.class));
}
return builder;
}
@ -186,6 +190,19 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
private URL determinePersistenceUnitRootLocation() {
Class<?> source = getClass();
try {
URL url = source.getProtectionDomain().getCodeSource().getLocation();
return ResourceUtils.extractJarFileURL(url);
}
catch (Exception ex) {
logger.info("Could not determine persistence "
+ "unit root location from " + source + " : " + ex);
}
return null;
}
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass(WebMvcConfigurerAdapter.class)

View File

@ -94,8 +94,8 @@ You can also use the `spring.main.banner-mode` property to determine if the bann
to be printed on `System.out` (`console`), using the configured logger (`log`) or not
at all (`off`).
The printed banner will be available via an `ApplicationInfo` registered as a singleton
bean under the name `springApplicationInfo`.
The printed banner will be registered as a singleton bean under the name
`springBootBanner`.
[NOTE]
====

View File

@ -11,9 +11,9 @@ welcome = { ->
// Try to print using the banner interface
if (beanFactory != null) {
try {
def appInfo = beanFactory.getBean("springApplicationInfo")
def banner = beanFactory.getBean("springBootBanner")
def out = new java.io.ByteArrayOutputStream()
appInfo.banner.printBanner(environment, null, new java.io.PrintStream(out))
banner.printBanner(environment, null, new java.io.PrintStream(out))
return out.toString()
} catch (Exception ex) {
// Ignore

View File

@ -1,65 +0,0 @@
/*
* Copyright 2012-2016 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;
/**
* Provide application-related information such as the {@link ApplicationArguments} and
* the {@link Banner}.
*
* @author Stephane Nicoll
* @since 1.4.1
*/
public final class ApplicationInfo {
private final Class<?> mainApplicationClass;
private final ApplicationArguments applicationArguments;
private final Banner banner;
protected ApplicationInfo(SpringApplication application,
ApplicationArguments applicationArguments, Banner banner) {
this.mainApplicationClass = application.getMainApplicationClass();
this.applicationArguments = applicationArguments;
this.banner = banner;
}
/**
* Returns the main application class that has been deduced or explicitly configured.
* @return the main application class or {@code null}
*/
public Class<?> getMainApplicationClass() {
return this.mainApplicationClass;
}
/**
* Returns the {@link ApplicationArguments} used to start this instance.
* @return the application arguments
*/
public ApplicationArguments getApplicationArguments() {
return this.applicationArguments;
}
/**
* Returns the {@link Banner} used by this instance.
* @return the banner or {@code null}
*/
public Banner getBanner() {
return this.banner;
}
}

View File

@ -359,10 +359,6 @@ public class SpringApplication {
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
ApplicationInfo applicationInfo = new ApplicationInfo(this, applicationArguments,
printedBanner);
context.getBeanFactory().registerSingleton("springApplicationInfo",
applicationInfo);
// Load the sources
Set<Object> sources = getSources();

View File

@ -28,12 +28,10 @@ import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.ApplicationInfo;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager;
import org.springframework.util.ClassUtils;
import org.springframework.util.ResourceUtils;
/**
* Convenient builder for JPA EntityManagerFactory instances. Collects common
@ -53,16 +51,16 @@ public class EntityManagerFactoryBuilder {
private static final Log logger = LogFactory
.getLog(EntityManagerFactoryBuilder.class);
private JpaVendorAdapter jpaVendorAdapter;
private final JpaVendorAdapter jpaVendorAdapter;
private PersistenceUnitManager persistenceUnitManager;
private final PersistenceUnitManager persistenceUnitManager;
private Map<String, Object> jpaProperties;
private final Map<String, Object> jpaProperties;
private final URL persistenceUnitRootLocation;
private EntityManagerFactoryBeanCallback callback;
private Class<?> applicationClass;
/**
* Create a new instance passing in the common pieces that will be shared if multiple
* EntityManagerFactory instances are created.
@ -73,9 +71,27 @@ public class EntityManagerFactoryBuilder {
*/
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
Map<String, ?> jpaProperties, PersistenceUnitManager persistenceUnitManager) {
this(jpaVendorAdapter, jpaProperties, persistenceUnitManager, null);
}
/**
* Create a new instance passing in the common pieces that will be shared if multiple
* EntityManagerFactory instances are created.
* @param jpaVendorAdapter a vendor adapter
* @param jpaProperties JPA properties to be passed to the persistence provider.
* @param persistenceUnitManager optional source of persistence unit information (can
* be null)
* @param persistenceUnitRootLocation the persistence unit root location to use as a
* fallback (can be null)
* @since 1.4.1
*/
public EntityManagerFactoryBuilder(JpaVendorAdapter jpaVendorAdapter,
Map<String, ?> jpaProperties, PersistenceUnitManager persistenceUnitManager,
URL persistenceUnitRootLocation) {
this.jpaVendorAdapter = jpaVendorAdapter;
this.persistenceUnitManager = persistenceUnitManager;
this.jpaProperties = new LinkedHashMap<String, Object>(jpaProperties);
this.persistenceUnitRootLocation = persistenceUnitRootLocation;
}
public Builder dataSource(DataSource dataSource) {
@ -90,33 +106,6 @@ public class EntityManagerFactoryBuilder {
this.callback = callback;
}
/**
* An optional {@link ApplicationInfo} used to further tune the entity manager.
* @param applicationInfo the application info
*/
public void setApplicationInfo(ApplicationInfo applicationInfo) {
this.applicationClass = applicationInfo.getMainApplicationClass();
}
/**
* Determine a persistence unit root location to use if no {@code persistence.xml} or
* {@code orm.xml} are present in the project.
* @return the persistence unit root location or {@code null}
*/
protected String determinePersistenceUnitRootLocation() {
if (this.applicationClass != null) {
try {
URL mainLocation = this.applicationClass.getProtectionDomain()
.getCodeSource().getLocation();
return ResourceUtils.extractJarFileURL(mainLocation).toString();
}
catch (Exception ex) {
logger.info("Could not determine persistence unit root location: " + ex);
}
}
return null;
}
/**
* A fluent builder for a LocalContainerEntityManagerFactoryBean.
*/
@ -220,9 +209,9 @@ public class EntityManagerFactoryBuilder {
entityManagerFactoryBean.getJpaPropertyMap()
.putAll(EntityManagerFactoryBuilder.this.jpaProperties);
entityManagerFactoryBean.getJpaPropertyMap().putAll(this.properties);
String rootLocation = determinePersistenceUnitRootLocation();
URL rootLocation = EntityManagerFactoryBuilder.this.persistenceUnitRootLocation;
if (rootLocation != null) {
entityManagerFactoryBean.setPersistenceUnitRootLocation(rootLocation);
entityManagerFactoryBean.setPersistenceUnitRootLocation(rootLocation.toString());
}
if (EntityManagerFactoryBuilder.this.callback != null) {
EntityManagerFactoryBuilder.this.callback

View File

@ -100,9 +100,6 @@ public class BannerTests {
application.setWebEnvironment(false);
this.context = application.run();
assertThat(this.context.containsBean("springBootBanner")).isTrue();
assertThat(this.context.containsBean("springApplicationInfo")).isTrue();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class)
.getBanner()).isNotNull();
}
@Test
@ -112,9 +109,7 @@ public class BannerTests {
Banner banner = mock(Banner.class);
application.setBanner(banner);
this.context = application.run();
ApplicationInfo applicationInfo = this.context.getBean("springApplicationInfo",
ApplicationInfo.class);
Banner printedBanner = applicationInfo.getBanner();
Banner printedBanner = (Banner) this.context.getBean("springBootBanner");
assertThat(ReflectionTestUtils.getField(printedBanner, "banner"))
.isEqualTo(banner);
verify(banner).printBanner(any(Environment.class),
@ -132,8 +127,6 @@ public class BannerTests {
application.setWebEnvironment(false);
this.context = application.run();
assertThat(this.context.containsBean("springBootBanner")).isFalse();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class)
.getBanner()).isNull();
}
@Test
@ -150,8 +143,6 @@ public class BannerTests {
this.context = application.run();
assertThat(this.out.toString()).contains("I printed a deprecated banner");
assertThat(this.context.containsBean("springBootBanner")).isFalse();
assertThat(this.context.getBean("springApplicationInfo", ApplicationInfo.class)
.getBanner()).isNull();
}
static class DummyBanner implements Banner {

View File

@ -778,21 +778,6 @@ public class SpringApplicationTests {
assertThat(System.getProperty("java.awt.headless")).isEqualTo("false");
}
@Test
public void getApplicationInfo() {
TestSpringApplication application = new TestSpringApplication(
ExampleConfig.class);
application.setWebEnvironment(false);
this.context = application.run("foo");
ApplicationInfo applicationInfo = this.context.getBean(ApplicationInfo.class);
assertThat(application.getMainApplicationClass())
.isEqualTo(application.getMainApplicationClass());
assertThat(applicationInfo.getApplicationArguments()).isNotNull();
assertThat(applicationInfo.getApplicationArguments().getNonOptionArgs())
.containsExactly("foo");
assertThat(applicationInfo.getBanner()).isNotNull();
}
@Test
public void getApplicationArgumentsBean() throws Exception {
TestSpringApplication application = new TestSpringApplication(