From 463174c1d8cd9fed939d35a37ea9eec5aac00023 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 8 Aug 2018 21:22:46 +0200 Subject: [PATCH] DATAJPA-1392 - Optimizations in JpaMetamodelMappingContext(FactoryBean) setup. We now avoid the eager scanning and addition of JPA managed types to create the JpaMetamodelMappingContext. We also avoid repeated lookups in the Metamodel as we assume the one used for the entity will also be the one that has to be used for all properties of that entity. --- .../mapping/JpaMetamodelMappingContext.java | 14 +++---- .../jpa/mapping/JpaPersistentEntityImpl.java | 13 ++++-- ...JpaMetamodelMappingContextFactoryBean.java | 38 +++++++---------- .../data/jpa/util/JpaMetamodel.java | 42 ++++--------------- ...JpaRepositoryConfigExtensionUnitTests.java | 6 --- 5 files changed, 38 insertions(+), 75 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java b/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java index 8c9a3177c..f60da8f5e 100644 --- a/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java +++ b/src/main/java/org/springframework/data/jpa/mapping/JpaMetamodelMappingContext.java @@ -63,7 +63,10 @@ public class JpaMetamodelMappingContext */ @Override protected JpaPersistentEntityImpl createPersistentEntity(TypeInformation typeInformation) { - return new JpaPersistentEntityImpl(typeInformation, persistenceProvider); + + Metamodel metamodel = getMetamodelFor(typeInformation.getType()); + + return new JpaPersistentEntityImpl(typeInformation, persistenceProvider, metamodel); } /* @@ -73,14 +76,7 @@ public class JpaMetamodelMappingContext @Override protected JpaPersistentProperty createPersistentProperty(Property property, JpaPersistentEntityImpl owner, SimpleTypeHolder simpleTypeHolder) { - - Metamodel metamodel = getMetamodelFor(owner.getType()); - - if (metamodel == null) { - throw new IllegalStateException(String.format("Metamodel for %s not available!", owner.getType())); - } - - return new JpaPersistentPropertyImpl(metamodel, property, owner, simpleTypeHolder); + return new JpaPersistentPropertyImpl(owner.getMetamodel(), property, owner, simpleTypeHolder); } /* diff --git a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentEntityImpl.java b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentEntityImpl.java index f3a0f25cd..44a1d02b5 100644 --- a/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentEntityImpl.java +++ b/src/main/java/org/springframework/data/jpa/mapping/JpaPersistentEntityImpl.java @@ -17,6 +17,8 @@ package org.springframework.data.jpa.mapping; import java.util.Comparator; +import javax.persistence.metamodel.Metamodel; + import org.springframework.data.annotation.Version; import org.springframework.data.jpa.provider.ProxyIdAccessor; import org.springframework.data.mapping.IdentifierAccessor; @@ -43,6 +45,7 @@ class JpaPersistentEntityImpl extends BasicPersistentEntity extends BasicPersistentEntity information, ProxyIdAccessor proxyIdAccessor) { + public JpaPersistentEntityImpl(TypeInformation information, ProxyIdAccessor proxyIdAccessor, Metamodel metamodel) { super(information, null); Assert.notNull(proxyIdAccessor, "ProxyIdAccessor must not be null!"); this.proxyIdAccessor = proxyIdAccessor; + this.metamodel = metamodel; } /* @@ -92,6 +96,10 @@ class JpaPersistentEntityImpl extends BasicPersistentEntity extends BasicPersistentEntity entity, Object bean, - ProxyIdAccessor proxyIdAccessor) { + JpaProxyAwareIdentifierAccessor(JpaPersistentEntity entity, Object bean, ProxyIdAccessor proxyIdAccessor) { super(entity, bean); diff --git a/src/main/java/org/springframework/data/jpa/repository/config/JpaMetamodelMappingContextFactoryBean.java b/src/main/java/org/springframework/data/jpa/repository/config/JpaMetamodelMappingContextFactoryBean.java index fd6c42164..f108047f2 100644 --- a/src/main/java/org/springframework/data/jpa/repository/config/JpaMetamodelMappingContextFactoryBean.java +++ b/src/main/java/org/springframework/data/jpa/repository/config/JpaMetamodelMappingContextFactoryBean.java @@ -16,13 +16,13 @@ package org.springframework.data.jpa.repository.config; import java.util.Collection; -import java.util.HashSet; import java.util.Set; import javax.persistence.EntityManagerFactory; -import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.beans.factory.FactoryBean; @@ -31,6 +31,7 @@ import org.springframework.beans.factory.config.AbstractFactoryBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext; +import org.springframework.data.util.StreamUtils; import org.springframework.lang.Nullable; /** @@ -43,6 +44,8 @@ import org.springframework.lang.Nullable; class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean implements ApplicationContextAware { + private static final Logger LOG = LoggerFactory.getLogger(JpaMetamodelMappingContextFactoryBean.class); + private @Nullable ListableBeanFactory beanFactory; /* @@ -70,25 +73,17 @@ class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean models = getMetamodels(); - Set> entitySources = new HashSet>(); - - for (Metamodel metamodel : models) { - - for (ManagedType type : metamodel.getManagedTypes()) { - - Class javaType = type.getJavaType(); - - if (javaType != null) { - entitySources.add(javaType); - } - } + if (LOG.isDebugEnabled()) { + LOG.debug("Initializing JpaMetamodelMappingContext…"); } - JpaMetamodelMappingContext context = new JpaMetamodelMappingContext(models); - context.setInitialEntitySet(entitySources); + JpaMetamodelMappingContext context = new JpaMetamodelMappingContext(getMetamodels()); context.initialize(); + if (LOG.isDebugEnabled()) { + LOG.debug("Finished initializing JpaMetamodelMappingContext!"); + } + return context; } @@ -105,12 +100,9 @@ class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean factories = BeanFactoryUtils .beansOfTypeIncludingAncestors(beanFactory, EntityManagerFactory.class).values(); - Set metamodels = new HashSet(factories.size()); - for (EntityManagerFactory emf : factories) { - metamodels.add(emf.getMetamodel()); - } - - return metamodels; + return factories.stream() // + .map(EntityManagerFactory::getMetamodel) // + .collect(StreamUtils.toUnmodifiableSet()); } } diff --git a/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java b/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java index 3b3ee202e..912158b17 100644 --- a/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java +++ b/src/main/java/org/springframework/data/jpa/util/JpaMetamodel.java @@ -16,16 +16,15 @@ package org.springframework.data.jpa.util; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; import java.util.Optional; -import java.util.Set; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; import javax.persistence.metamodel.SingularAttribute; +import org.springframework.data.util.Lazy; +import org.springframework.data.util.StreamUtils; import org.springframework.util.Assert; /** @@ -38,7 +37,7 @@ public class JpaMetamodel { private final Metamodel metamodel; - private Optional>> managedTypes = Optional.empty(); + private Lazy>> managedTypes; /** * Creates a new {@link JpaMetamodel} for the given JPA {@link Metamodel}. @@ -50,6 +49,10 @@ public class JpaMetamodel { Assert.notNull(metamodel, "Metamodel must not be null!"); this.metamodel = metamodel; + this.managedTypes = Lazy.of(() -> metamodel.getManagedTypes().stream() // + .map(ManagedType::getJavaType) // + .filter(it -> it != null) // + .collect(StreamUtils.toUnmodifiableSet())); } /** @@ -62,7 +65,7 @@ public class JpaMetamodel { Assert.notNull(type, "Type must not be null!"); - return getManagedTypes().contains(type); + return managedTypes.get().contains(type); } /** @@ -84,35 +87,6 @@ public class JpaMetamodel { .orElse(false); } - /** - * Returns all types managed by the backing {@link Metamodel}. Skips {@link ManagedType} instances that return - * {@literal null} for calls to {@link ManagedType#getJavaType()}. - * - * @return all managed types. - * @see HHH-10968 - */ - private Collection> getManagedTypes() { - - if (!managedTypes.isPresent()) { - - Set> managedTypes = metamodel.getManagedTypes(); - Set> types = new HashSet>(managedTypes.size()); - - for (ManagedType managedType : metamodel.getManagedTypes()) { - - Class type = managedType.getJavaType(); - - if (type != null) { - types.add(type); - } - } - - this.managedTypes = Optional.of(Collections.unmodifiableSet(types)); - } - - return this.managedTypes.get(); - } - /** * Returns the {@link SingularAttribute} representing the identifier of the given {@link EntityType} if it contains a * singular one. diff --git a/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java index 4570dac4d..2ab5c21c4 100644 --- a/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/config/JpaRepositoryConfigExtensionUnitTests.java @@ -22,10 +22,8 @@ import static org.mockito.Mockito.*; import java.util.Arrays; import java.util.Collections; -import java.util.Set; import javax.persistence.EntityManagerFactory; -import javax.persistence.metamodel.ManagedType; import javax.persistence.metamodel.Metamodel; import org.junit.Rule; @@ -100,13 +98,9 @@ public class JpaRepositoryConfigExtensionUnitTests { ApplicationContext context = mock(ApplicationContext.class); EntityManagerFactory emf = mock(EntityManagerFactory.class); Metamodel metamodel = mock(Metamodel.class); - ManagedType managedType = mock(ManagedType.class); - - Set> managedTypes = Collections.> singleton(managedType); when(context.getBeansOfType(EntityManagerFactory.class)).thenReturn(Collections.singletonMap("emf", emf)); when(emf.getMetamodel()).thenReturn(metamodel); - when(metamodel.getManagedTypes()).thenReturn(managedTypes); JpaMetamodelMappingContextFactoryBean factoryBean = new JpaMetamodelMappingContextFactoryBean(); factoryBean.setApplicationContext(context);