Skip to content

Commit a91a27a

Browse files
committed
DATAJPA-813 - Improved EntityManagerFactory detection for JndiObjectFactoryBeans.
The lookup of EntityManagerFactory bean definition now also detects JndiObjectFactoryBean instances that have the expected type configured to EntityManagerFactory. Related ticket: DATACMNS-821.
1 parent e64d28e commit a91a27a

File tree

4 files changed

+91
-25
lines changed

4 files changed

+91
-25
lines changed

src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2014 the original author or authors.
2+
* Copyright 2014-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,8 +19,8 @@
1919
import static org.springframework.beans.factory.BeanFactoryUtils.*;
2020

2121
import java.util.ArrayList;
22-
import java.util.Arrays;
2322
import java.util.Collection;
23+
import java.util.Collections;
2424
import java.util.HashSet;
2525
import java.util.List;
2626
import java.util.Set;
@@ -33,7 +33,9 @@
3333
import org.springframework.beans.factory.config.BeanDefinition;
3434
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
3535
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
36+
import org.springframework.jndi.JndiObjectFactoryBean;
3637
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
38+
import org.springframework.util.ClassUtils;
3739

3840
/**
3941
* Utility methods to work with {@link BeanDefinition} instances from {@link BeanFactoryPostProcessor}s.
@@ -42,6 +44,22 @@
4244
*/
4345
public class BeanDefinitionUtils {
4446

47+
private static final String JNDI_OBJECT_FACTORY_BEAN = "org.springframework.jndi.JndiObjectFactoryBean";
48+
private static final List<Class<?>> EMF_TYPES;
49+
50+
static {
51+
52+
List<Class<?>> types = new ArrayList<Class<?>>();
53+
types.add(EntityManagerFactory.class);
54+
types.add(AbstractEntityManagerFactoryBean.class);
55+
56+
if (ClassUtils.isPresent(JNDI_OBJECT_FACTORY_BEAN, ClassUtils.getDefaultClassLoader())) {
57+
types.add(JndiObjectFactoryBean.class);
58+
}
59+
60+
EMF_TYPES = Collections.unmodifiableList(types);
61+
}
62+
4563
/**
4664
* Return all bean names for bean definitions that will result in an {@link EntityManagerFactory} eventually. We're
4765
* checking for {@link EntityManagerFactory} and the well-known factory beans here to avoid eager initialization of
@@ -71,24 +89,15 @@ public static Iterable<String> getEntityManagerFactoryBeanNames(ListableBeanFact
7189
* @param beanFactory must not be {@literal null}.
7290
* @return
7391
*/
74-
@SuppressWarnings("unchecked")
7592
public static Collection<EntityManagerFactoryBeanDefinition> getEntityManagerFactoryBeanDefinitions(
7693
ConfigurableListableBeanFactory beanFactory) {
7794

7895
List<EntityManagerFactoryBeanDefinition> definitions = new ArrayList<EntityManagerFactoryBeanDefinition>();
7996

80-
for (Class<?> type : Arrays.asList(EntityManagerFactory.class, AbstractEntityManagerFactoryBean.class)) {
97+
for (Class<?> type : EMF_TYPES) {
8198

8299
for (String name : beanFactory.getBeanNamesForType(type, true, false)) {
83-
84-
String transformedName = transformedBeanName(name);
85-
86-
EntityManagerFactoryBeanDefinition definition = new EntityManagerFactoryBeanDefinition( //
87-
transformedName, //
88-
beanFactory, //
89-
beanFactory.getBeanDefinition(transformedName));
90-
91-
definitions.add(definition);
100+
registerEntityManagerFactoryBeanDefinition(transformedBeanName(name), beanFactory, definitions);
92101
}
93102
}
94103

@@ -101,6 +110,28 @@ public static Collection<EntityManagerFactoryBeanDefinition> getEntityManagerFac
101110
return definitions;
102111
}
103112

113+
/**
114+
* Registers an {@link EntityManagerFactoryBeanDefinition} for the bean with the given name. Drops
115+
* {@link JndiObjectFactoryBean} instances that don't point to an {@link EntityManagerFactory} bean as expected type.
116+
*
117+
* @param name
118+
* @param beanFactory
119+
* @param definitions
120+
*/
121+
private static void registerEntityManagerFactoryBeanDefinition(String name,
122+
ConfigurableListableBeanFactory beanFactory, List<EntityManagerFactoryBeanDefinition> definitions) {
123+
124+
BeanDefinition definition = beanFactory.getBeanDefinition(name);
125+
126+
if (JNDI_OBJECT_FACTORY_BEAN.equals(definition.getBeanClassName())) {
127+
if (!definition.getPropertyValues().get("expectedType").equals(EntityManagerFactory.class.getName())) {
128+
return;
129+
}
130+
}
131+
132+
definitions.add(new EntityManagerFactoryBeanDefinition(name, beanFactory));
133+
}
134+
104135
/**
105136
* Returns the {@link BeanDefinition} with the given name, obtained from the given {@link BeanFactory} or one of its
106137
* parents.
@@ -134,21 +165,18 @@ public static BeanDefinition getBeanDefinition(String name, ConfigurableListable
134165
public static class EntityManagerFactoryBeanDefinition {
135166

136167
private final String beanName;
137-
private final BeanFactory beanFactory;
138-
private final BeanDefinition beanDefinition;
168+
private final ConfigurableListableBeanFactory beanFactory;
139169

140170
/**
141171
* Creates a new {@link EntityManagerFactoryBeanDefinition}.
142172
*
143173
* @param beanName
144174
* @param beanFactory
145-
* @param beanDefinition
146175
*/
147-
public EntityManagerFactoryBeanDefinition(String beanName, BeanFactory beanFactory, BeanDefinition beanDefinition) {
176+
public EntityManagerFactoryBeanDefinition(String beanName, ConfigurableListableBeanFactory beanFactory) {
148177

149178
this.beanName = beanName;
150179
this.beanFactory = beanFactory;
151-
this.beanDefinition = beanDefinition;
152180
}
153181

154182
/**
@@ -175,7 +203,7 @@ public BeanFactory getBeanFactory() {
175203
* @return
176204
*/
177205
public BeanDefinition getBeanDefinition() {
178-
return beanDefinition;
206+
return beanFactory.getBeanDefinition(beanName);
179207
}
180208
}
181209
}

src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2014 the original author or authors.
2+
* Copyright 2013-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@
2727
import javax.persistence.metamodel.ManagedType;
2828
import javax.persistence.metamodel.Metamodel;
2929

30-
import org.hamcrest.Matchers;
3130
import org.junit.Rule;
3231
import org.junit.Test;
3332
import org.junit.rules.ExpectedException;
@@ -42,6 +41,7 @@
4241
import org.springframework.context.annotation.AnnotationConfigUtils;
4342
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
4443
import org.springframework.data.repository.config.RepositoryConfigurationSource;
44+
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
4545
import org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor;
4646

4747
/**
@@ -52,11 +52,11 @@
5252
@RunWith(MockitoJUnitRunner.class)
5353
public class JpaRepositoryConfigExtensionUnitTests {
5454

55-
private static final String RIABPP_CLASS_NAME = "org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor";
55+
private static final String RIABPP_CLASS_NAME = RepositoryFactoryBeanSupport.class.getName().concat("_Predictor");
5656

5757
@Mock RepositoryConfigurationSource configSource;
5858

59-
@Rule public ExpectedException exception = ExpectedException.none();
59+
public @Rule ExpectedException exception = ExpectedException.none();
6060

6161
@Test
6262
public void registersDefaultBeanPostProcessorsByDefault() {
@@ -68,8 +68,7 @@ public void registersDefaultBeanPostProcessorsByDefault() {
6868

6969
Iterable<String> names = Arrays.asList(factory.getBeanDefinitionNames());
7070

71-
assertThat(names, Matchers.<String> hasItem(AnnotationConfigUtils.PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
72-
assertThat(names, Matchers.<String> hasItem(RIABPP_CLASS_NAME));
71+
assertThat(names, hasItems(AnnotationConfigUtils.PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME, RIABPP_CLASS_NAME));
7372
}
7473

7574
@Test

src/test/java/org/springframework/data/jpa/repository/support/DefaultJpaContextIntegrationTests.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@
3737
import org.springframework.context.annotation.ComponentScan;
3838
import org.springframework.context.annotation.ComponentScan.Filter;
3939
import org.springframework.context.annotation.FilterType;
40+
import org.springframework.context.support.ClassPathXmlApplicationContext;
4041
import org.springframework.data.jpa.domain.sample.Category;
4142
import org.springframework.data.jpa.domain.sample.User;
4243
import org.springframework.data.jpa.repository.JpaContext;
4344
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
4445
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
4546
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
47+
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
4648
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
4749
import org.springframework.stereotype.Component;
4850

@@ -123,6 +125,23 @@ public void bootstrapsDefaultJpaContextInSpringContainer() {
123125
context.close();
124126
}
125127

128+
/**
129+
* @see DATAJPA-813
130+
*/
131+
@Test
132+
public void bootstrapsDefaultJpaContextInSpringContainerWithEntityManagerFromJndi() throws Exception {
133+
134+
SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
135+
builder.bind("some/EMF", createEntityManagerFactory("spring-data-jpa"));
136+
137+
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("config/jpa-context-with-jndi.xml");
138+
ApplicationComponent component = context.getBean(ApplicationComponent.class);
139+
140+
assertThat(component.context, is(notNullValue()));
141+
142+
context.close();
143+
}
144+
126145
private static final LocalContainerEntityManagerFactoryBean createEntityManagerFactoryBean(
127146
String persistenceUnitName) {
128147

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
5+
xmlns:jee="http://www.springframework.org/schema/jee"
6+
xmlns:context="http://www.springframework.org/schema/context"
7+
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
8+
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
9+
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
10+
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
11+
12+
<jpa:repositories base-package="org.springframework.data.jpa.repository.support" />
13+
14+
<jee:jndi-lookup id="entityManagerFactory"
15+
jndi-name="some/EMF"
16+
expected-type="javax.persistence.EntityManagerFactory" />
17+
18+
<bean class="org.springframework.data.jpa.repository.support.DefaultJpaContextIntegrationTests$ApplicationComponent" autowire="constructor" />
19+
20+
</beans>

0 commit comments

Comments
 (0)