DATAJPA-630 - Add IdentifierAccessor implementation that avoids proxy resolution for id lookups.

We now customize the IdentifierAccessor returned from JpaPersistentEntity.getIdentifierAccessor(…) to allow the identifier lookup use persistence provider specific means. This is needed to make sure we lookup identifiers for proxies correctly for which a field value lookup would not succeed (as the providers do not pre-populate the identifier field).
This commit is contained in:
Oliver Gierke
2014-11-24 13:32:44 +01:00
parent b09078f53b
commit cd6d7b6e5b
40 changed files with 815 additions and 265 deletions

View File

@@ -17,7 +17,6 @@ package org.springframework.data.jpa.mapping;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Set;
import javax.persistence.metamodel.ManagedType;
@@ -49,11 +48,8 @@ public class JpaMetamodelMappingContext extends
Assert.notNull(models, "JPA metamodel must not be null!");
Assert.notEmpty(models, "At least one JPA metamodel must be present!");
this.models = models;
}
public JpaMetamodelMappingContext(Metamodel model) {
this(Collections.singleton(model));
this.models = models;
}
/*
@@ -62,7 +58,7 @@ public class JpaMetamodelMappingContext extends
*/
@Override
protected <T> JpaPersistentEntityImpl<?> createPersistentEntity(TypeInformation<T> typeInformation) {
return new JpaPersistentEntityImpl<T>(typeInformation, null);
return new JpaPersistentEntityImpl<T>(typeInformation, getMetamodelFor(typeInformation.getType()));
}
/*

View File

@@ -17,8 +17,15 @@ package org.springframework.data.jpa.mapping;
import java.util.Comparator;
import javax.persistence.metamodel.Metamodel;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.provider.ProxyIdAccessor;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.mapping.model.IdPropertyIdentifierAccessor;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
/**
* Implementation of {@link JpaPersistentEntity}.
@@ -29,14 +36,20 @@ import org.springframework.data.util.TypeInformation;
class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentProperty> implements
JpaPersistentEntity<T> {
private final ProxyIdAccessor proxyIdAccessor;
/**
* Creates a new {@link JpaPersistentEntityImpl} using the given {@link TypeInformation} and {@link Comparator}.
*
* @param information must not be {@literal null}.
* @param comparator must not be {@literal null}.
* @param metamodel must not be {@literal null}.
*/
public JpaPersistentEntityImpl(TypeInformation<T> information, Comparator<JpaPersistentProperty> comparator) {
super(information, comparator);
public JpaPersistentEntityImpl(TypeInformation<T> information, Metamodel metamodel) {
super(information, null);
Assert.notNull(metamodel, "Metamodel must not be null!");
this.proxyIdAccessor = PersistenceProvider.fromMetamodel(metamodel);
}
/*
@@ -47,4 +60,54 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
protected JpaPersistentProperty returnPropertyIfBetterIdPropertyCandidateOrNull(JpaPersistentProperty property) {
return property.isIdProperty() ? property : null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.model.BasicPersistentEntity#getIdentifierAccessor(java.lang.Object)
*/
@Override
public IdentifierAccessor getIdentifierAccessor(Object bean) {
return new JpaProxyAwareIdentifierAccessor(this, bean, proxyIdAccessor);
}
/**
* {@link IdentifierAccessor} that tries to use a {@link ProxyIdAccessor} for id access to potentially avoid the
* initialization of JPA proxies. We're falling back to the default behavior of {@link IdPropertyIdentifierAccessor}
* if that's not possible.
*
* @author Oliver Gierke
*/
private static class JpaProxyAwareIdentifierAccessor extends IdPropertyIdentifierAccessor {
private final Object bean;
private final ProxyIdAccessor proxyIdAccessor;
/**
* Creates a new {@link JpaProxyAwareIdentifierAccessor} for the given {@link JpaPersistentEntity}, target bean and
* {@link ProxyIdAccessor}.
*
* @param entity must not be {@literal null}.
* @param bean must not be {@literal null}.
* @param proxyIdAccessor must not be {@literal null}.
*/
public JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean, ProxyIdAccessor proxyIdAccessor) {
super(entity, bean);
Assert.notNull(proxyIdAccessor, "Proxy identifier accessor must not be null!");
this.proxyIdAccessor = proxyIdAccessor;
this.bean = bean;
}
/*
* (non-Javadoc)
* @see org.springframework.data.mapping.IdentifierAccessor#getIdentifier()
*/
@Override
public Object getIdentifier() {
return proxyIdAccessor.shouldUseAccessorFor(bean) ? proxyIdAccessor.getIdentifierFrom(bean) : super
.getIdentifier();
}
}
}

View File

@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.utils;
package org.springframework.data.jpa.provider;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.Metamodel;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -25,7 +26,7 @@ import org.springframework.util.ClassUtils;
*
* @author Oliver Gierke
*/
public abstract class JpaClassUtils {
abstract class JpaClassUtils {
/**
* Private constructor to prevent instantiation.
@@ -42,16 +43,21 @@ public abstract class JpaClassUtils {
* @return
*/
public static boolean isEntityManagerOfType(EntityManager em, String type) {
return isOfType(em, type, em.getDelegate().getClass().getClassLoader());
}
Assert.notNull(em, "EntityManager must not be null!");
Assert.hasText(type, "EntityManager type must not be null!");
public static boolean isMetamodelOfType(Metamodel metamodel, String type) {
return isOfType(metamodel, type, metamodel.getClass().getClassLoader());
}
private static boolean isOfType(Object source, String typeName, ClassLoader classLoader) {
Assert.notNull(source, "Source instance must not be null!");
Assert.hasText(typeName, "Target type name must not be null or empty!");
try {
ClassLoader loader = em.getDelegate().getClass().getClassLoader();
Class<?> emType = ClassUtils.forName(type, loader);
emType.cast(em);
ClassUtils.forName(typeName, classLoader).cast(source);
return true;
} catch (Exception e) {

View File

@@ -0,0 +1,284 @@
/*
* Copyright 2008-2014 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.data.jpa.provider;
import static org.springframework.data.jpa.provider.JpaClassUtils.*;
import static org.springframework.data.jpa.provider.PersistenceProvider.Constants.*;
import java.util.Arrays;
import java.util.Collections;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.metamodel.Metamodel;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.persistence.OpenJPAQuery;
import org.eclipse.persistence.jpa.JpaQuery;
import org.hibernate.ejb.HibernateQuery;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.util.Assert;
/**
* Enumeration representing persistence providers to be used.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
/**
* Hibernate persistence provider.
* <p>
* Since Hibernate 4.3 the location of the HibernateEntityManager moved to the org.hibernate.jpa package. In order to
* support both locations we interpret both classnames as a Hibernate {@code PersistenceProvider}.
*
* @see DATAJPA-444
*/
HIBERNATE(//
Arrays.asList(HIBERNATE43_ENTITY_MANAGER_INTERFACE, HIBERNATE_ENTITY_MANAGER_INTERFACE), //
Arrays.asList(HIBERNATE43_JPA_METAMODEL_TYPE, HIBERNATE_JPA_METAMODEL_TYPE)) {
public String extractQueryString(Query query) {
return ((HibernateQuery) query).getHibernateQuery().getQueryString();
}
/**
* Return custom placeholder ({@code *}) as Hibernate does create invalid queries for count queries for objects with
* compound keys.
*
* @see HHH-4044
* @see HHH-3096
*/
@Override
public String getCountQueryPlaceholder() {
return "*";
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#isProxy(java.lang.Object)
*/
@Override
public boolean shouldUseAccessorFor(Object entity) {
return entity instanceof HibernateProxy;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#getIdentifierFrom(java.lang.Object)
*/
@Override
public Object getIdentifierFrom(Object entity) {
return ((HibernateProxy) entity).getHibernateLazyInitializer().getIdentifier();
}
},
/**
* EclipseLink persistence provider.
*/
ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE), Collections
.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
public String extractQueryString(Query query) {
return ((JpaQuery<?>) query).getDatabaseQuery().getJPQLString();
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#isProxy(java.lang.Object)
*/
@Override
public boolean shouldUseAccessorFor(Object entity) {
return false;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#getIdentifierFrom(java.lang.Object)
*/
@Override
public Object getIdentifierFrom(Object entity) {
return null;
}
},
/**
* OpenJpa persistence provider.
*/
OPEN_JPA(Collections.singleton(OPENJPA_ENTITY_MANAGER_INTERFACE), Collections.singleton(OPENJPA_JPA_METAMODEL_TYPE)) {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.QueryExtractor#extractQueryString(javax.persistence.Query)
*/
@Override
public String extractQueryString(Query query) {
return ((OpenJPAQuery<?>) query).getQueryString();
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#isProxy(java.lang.Object)
*/
@Override
public boolean shouldUseAccessorFor(Object entity) {
return entity instanceof PersistenceCapable;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#getIdentifierFrom(java.lang.Object)
*/
@Override
public Object getIdentifierFrom(Object entity) {
return ((PersistenceCapable) entity).pcFetchObjectId();
}
},
/**
* Unknown special provider. Use standard JPA.
*/
GENERIC_JPA(Collections.singleton(GENERIC_JPA_ENTITY_MANAGER_INTERFACE), Collections.<String> emptySet()) {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.QueryExtractor#extractQueryString(javax.persistence.Query)
*/
@Override
public String extractQueryString(Query query) {
return null;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.PersistenceProvider#canExtractQuery()
*/
@Override
public boolean canExtractQuery() {
return false;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#isProxy(java.lang.Object)
*/
@Override
public boolean shouldUseAccessorFor(Object entity) {
return false;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#getIdentifierFrom(java.lang.Object)
*/
@Override
public Object getIdentifierFrom(Object entity) {
return null;
}
};
/**
* Holds the PersistenceProvider specific interface names.
*
* @author Thomas Darimont
*/
static interface Constants {
String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "javax.persistence.EntityManager";
String OPENJPA_ENTITY_MANAGER_INTERFACE = "org.apache.openjpa.persistence.OpenJPAEntityManager";
String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager";
String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.ejb.HibernateEntityManager";
String HIBERNATE43_ENTITY_MANAGER_INTERFACE = "org.hibernate.jpa.HibernateEntityManager";
String HIBERNATE_JPA_METAMODEL_TYPE = "org.hibernate.ejb.metamodel.MetamodelImpl";
String HIBERNATE43_JPA_METAMODEL_TYPE = "org.hibernate.jpa.internal.metamodel.MetamodelImpl";
String ECLIPSELINK_JPA_METAMODEL_TYPE = "org.eclipse.persistence.internal.jpa.metamodel.MetamodelImpl";
String OPENJPA_JPA_METAMODEL_TYPE = "org.apache.openjpa.persistence.meta.MetamodelImpl";
}
private final Iterable<String> entityManagerClassNames;
private final Iterable<String> metamodelClassNames;
/**
* Creates a new {@link PersistenceProvider}.
*
* @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
* be {@literal null} or empty.
*/
private PersistenceProvider(Iterable<String> entityManagerClassNames, Iterable<String> metamodelClassNames) {
this.entityManagerClassNames = entityManagerClassNames;
this.metamodelClassNames = metamodelClassNames;
}
/**
* Determines the {@link PersistenceProvider} from the given {@link EntityManager}. If no special one can be
* determined {@link #GENERIC_JPA} will be returned.
*
* @param em must not be {@literal null}.
* @return will never be {@literal null}.
*/
public static PersistenceProvider fromEntityManager(EntityManager em) {
Assert.notNull(em);
for (PersistenceProvider provider : values()) {
for (String entityManagerClassName : provider.entityManagerClassNames) {
if (isEntityManagerOfType(em, entityManagerClassName)) {
return provider;
}
}
}
return GENERIC_JPA;
}
public static PersistenceProvider fromMetamodel(Metamodel metamodel) {
Assert.notNull(metamodel, "Metamodel must not be null!");
for (PersistenceProvider provider : values()) {
for (String metamodelClassName : provider.metamodelClassNames) {
if (isMetamodelOfType(metamodel, metamodelClassName)) {
return provider;
}
}
}
return GENERIC_JPA;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.jpa.repository.query.QueryExtractor#canExtractQuery
* ()
*/
public boolean canExtractQuery() {
return true;
}
/**
* Returns the placeholder to be used for simple count queries. Default implementation returns {@code *}.
*
* @return
*/
public String getCountQueryPlaceholder() {
return "x";
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 2014 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.data.jpa.provider;
/**
* Interface for a persistence provider specific accessor of identifiers held in proxies.
*
* @author Oliver Gierke
*/
public interface ProxyIdAccessor {
/**
* Returns whether the {@link ProxyIdAccessor} should be used for the given entity. Will inspect the entity to see
* whether it is a proxy so that lenient id lookup can be used.
*
* @param entity must not be {@literal null}.
* @return
*/
boolean shouldUseAccessorFor(Object entity);
/**
* Returns the identifier of the given entity by leniently inspecting it for the identifier value.
*
* @param entity must not be {@literal null}.
* @return
*/
Object getIdentifierFrom(Object entity);
}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.query;
package org.springframework.data.jpa.provider;
import javax.persistence.Query;

View File

@@ -19,6 +19,7 @@ import java.lang.reflect.Method;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.EvaluationContextProvider;

View File

@@ -29,6 +29,7 @@ import javax.persistence.LockModeType;
import javax.persistence.QueryHint;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Modifying;

View File

@@ -21,6 +21,7 @@ import javax.persistence.TypedQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.data.repository.query.RepositoryQuery;

View File

@@ -54,7 +54,7 @@ public abstract class JpaEntityInformationSupport<T, ID extends Serializable> ex
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> JpaEntityInformation<T, ?> getMetadata(Class<T> domainClass, EntityManager em) {
public static <T> JpaEntityInformation<T, ?> getEntityInformation(Class<T> domainClass, EntityManager em) {
Assert.notNull(domainClass);
Assert.notNull(em);

View File

@@ -21,9 +21,10 @@ import java.io.Serializable;
import javax.persistence.EntityManager;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy;
import org.springframework.data.jpa.repository.query.QueryExtractor;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
@@ -142,6 +143,6 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> JpaEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
return (JpaEntityInformation<T, ID>) JpaEntityInformationSupport.getMetadata(domainClass, entityManager);
return (JpaEntityInformation<T, ID>) JpaEntityInformationSupport.getEntityInformation(domainClass, entityManager);
}
}

View File

@@ -1,182 +0,0 @@
/*
* Copyright 2008-2014 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.data.jpa.repository.support;
import static org.springframework.data.jpa.repository.utils.JpaClassUtils.*;
import java.util.Arrays;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.openjpa.persistence.OpenJPAQuery;
import org.eclipse.persistence.jpa.JpaQuery;
import org.hibernate.ejb.HibernateQuery;
import org.springframework.data.jpa.repository.query.QueryExtractor;
import org.springframework.util.Assert;
/**
* Enumeration representing persistence providers to be used.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
public enum PersistenceProvider implements QueryExtractor {
/**
* Hibernate persistence provider.
* <p>
* Since Hibernate 4.3 the location of the HibernateEntityManager moved to the org.hibernate.jpa package. In order to
* support both locations we interpret both classnames as a Hibernate {@code PersistenceProvider}.
*
* @see DATAJPA-444
*/
HIBERNATE(Constants.HIBERNATE43_ENTITY_MANAGER_INTERFACE, Constants.HIBERNATE_ENTITY_MANAGER_INTERFACE) {
public String extractQueryString(Query query) {
return ((HibernateQuery) query).getHibernateQuery().getQueryString();
}
/**
* Return custom placeholder ({@code *}) as Hibernate does create invalid queries for count queries for objects with
* compound keys.
*
* @see HHH-4044
* @see HHH-3096
*/
@Override
protected String getCountQueryPlaceholder() {
return "*";
}
},
/**
* EclipseLink persistence provider.
*/
ECLIPSELINK(Constants.ECLIPSELINK_ENTITY_MANAGER_INTERFACE) {
public String extractQueryString(Query query) {
return ((JpaQuery<?>) query).getDatabaseQuery().getJPQLString();
}
},
/**
* OpenJpa persistence provider.
*/
OPEN_JPA(Constants.OPENJPA_ENTITY_MANAGER_INTERFACE) {
public String extractQueryString(Query query) {
return ((OpenJPAQuery<?>) query).getQueryString();
}
},
/**
* Unknown special provider. Use standard JPA.
*/
GENERIC_JPA(Constants.GENERIC_JPA_ENTITY_MANAGER_INTERFACE) {
public String extractQueryString(Query query) {
return null;
}
@Override
public boolean canExtractQuery() {
return false;
}
};
/**
* Holds the PersistenceProvider specific interface names.
*
* @author Thomas Darimont
*/
static interface Constants {
String GENERIC_JPA_ENTITY_MANAGER_INTERFACE = "javax.persistence.EntityManager";
String OPENJPA_ENTITY_MANAGER_INTERFACE = "org.apache.openjpa.persistence.OpenJPAEntityManager";
String ECLIPSELINK_ENTITY_MANAGER_INTERFACE = "org.eclipse.persistence.jpa.JpaEntityManager";
String HIBERNATE_ENTITY_MANAGER_INTERFACE = "org.hibernate.ejb.HibernateEntityManager";
String HIBERNATE43_ENTITY_MANAGER_INTERFACE = "org.hibernate.jpa.HibernateEntityManager";
}
private List<String> entityManagerClassNames;
/**
* Creates a new {@link PersistenceProvider}.
*
* @param entityManagerClassNames the names of the provider specific {@link EntityManager} implementations. Must not
* be {@literal null} or empty.
*/
private PersistenceProvider(String... entityManagerClassNames) {
Assert.notEmpty(entityManagerClassNames, "EntityManagerClassNames must not be empty!");
this.entityManagerClassNames = Arrays.asList(entityManagerClassNames);
}
/**
* Determines the {@link PersistenceProvider} from the given {@link EntityManager}. If no special one can be
* determined {@link #GENERIC_JPA} will be returned.
*
* @param em must not be {@literal null}.
* @return will never be {@literal null}.
*/
public static PersistenceProvider fromEntityManager(EntityManager em) {
Assert.notNull(em);
for (PersistenceProvider provider : values()) {
for (String entityManagerClassName : provider.entityManagerClassNames) {
if (isEntityManagerOfType(em, entityManagerClassName)) {
return provider;
}
}
}
return GENERIC_JPA;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.data.jpa.repository.query.QueryExtractor#canExtractQuery
* ()
*/
public boolean canExtractQuery() {
return true;
}
/**
* Returns the placeholder to be used for simple count queries. Default implementation returns {@code *}.
*
* @return
*/
protected String getCountQueryPlaceholder() {
return "x";
}
}

View File

@@ -22,6 +22,7 @@ import javax.persistence.EntityManager;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.querydsl.QSort;
import org.springframework.util.Assert;

View File

@@ -42,6 +42,7 @@ import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.query.Jpa21Utils;
@@ -96,7 +97,7 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
* @param em must not be {@literal null}.
*/
public SimpleJpaRepository(Class<T> domainClass, EntityManager em) {
this(JpaEntityInformationSupport.getMetadata(domainClass, em), em);
this(JpaEntityInformationSupport.getEntityInformation(domainClass, em), em);
}
/**

View File

@@ -0,0 +1,30 @@
package org.springframework.data.jpa.domain.sample;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Category {
@Id @GeneratedValue private Long id;
@ManyToOne(fetch = FetchType.LAZY)//
private Product product;
public Category(Product product) {
this.product = product;
}
protected Category() {}
public Long getId() {
return id;
}
public Product getProduct() {
return product;
}
}

View File

@@ -0,0 +1,15 @@
package org.springframework.data.jpa.domain.sample;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Product {
@Id @GeneratedValue private Long id;
public Long getId() {
return id;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012 the original author or authors.
* Copyright 2012-2014 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.
@@ -18,15 +18,32 @@ package org.springframework.data.jpa.mapping;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.Collections;
import javax.persistence.EntityManager;
import org.hibernate.proxy.HibernateProxy;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.jpa.domain.sample.Category;
import org.springframework.data.jpa.domain.sample.Product;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.sample.CategoryRepository;
import org.springframework.data.jpa.repository.sample.ProductRepository;
import org.springframework.data.mapping.IdentifierAccessor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
/**
* Integration tests for {@link JpaMetamodelMappingContext}.
@@ -35,16 +52,28 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @since 1.3
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:infrastructure.xml")
@ContextConfiguration
public class JpaMetamodelMappingContextIntegrationTests {
@Configuration
@ImportResource("classpath:infrastructure.xml")
@EnableJpaRepositories(basePackageClasses = CategoryRepository.class,//
includeFilters = @Filter(value = { CategoryRepository.class, ProductRepository.class },
type = FilterType.ASSIGNABLE_TYPE))
static class Config {
}
JpaMetamodelMappingContext context;
@PersistenceContext EntityManager em;
@Autowired ProductRepository products;
@Autowired CategoryRepository categories;
@Autowired EntityManager em;
@Autowired PlatformTransactionManager transactionManager;
@Before
public void setUp() {
context = new JpaMetamodelMappingContext(em.getMetamodel());
context = new JpaMetamodelMappingContext(Collections.singleton(em.getMetamodel()));
}
@Test
@@ -95,4 +124,36 @@ public class JpaMetamodelMappingContextIntegrationTests {
assertThat(entity.getPersistentProperty("colleagues").isEntity(), is(true));
}
/**
* @see DATAJPA-630
*/
@Test
public void lookingUpIdentifierOfProxyDoesNotInitializeProxy() {
new TransactionTemplate(transactionManager).execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus status) {
Product product = products.save(new Product());
Category category = categories.save(new Category(product));
em.clear();
Category loaded = categories.findOne(category.getId());
Product loadedProduct = loaded.getProduct();
JpaPersistentEntity<?> entity = context.getPersistentEntity(Product.class);
IdentifierAccessor accessor = entity.getIdentifierAccessor(loadedProduct);
assertThat(accessor.getIdentifier(), is((Object) product.getId()));
assertThat(loadedProduct, is(instanceOf(HibernateProxy.class)));
assertThat(((HibernateProxy) loadedProduct).getHibernateLazyInitializer().isUninitialized(), is(true));
status.setRollbackOnly();
return null;
}
});
}
}

View File

@@ -18,6 +18,8 @@ package org.springframework.data.jpa.mapping;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.Collections;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Embeddable;
@@ -50,7 +52,7 @@ public class JpaPersistentPropertyImplUnitTests {
@Before
public void setUp() {
context = new JpaMetamodelMappingContext(model);
context = new JpaMetamodelMappingContext(Collections.singleton(model));
entity = context.getPersistentEntity(Sample.class);
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2014 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.data.jpa.provider;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import javax.persistence.EntityManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.jpa.domain.sample.Category;
import org.springframework.data.jpa.domain.sample.Product;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.provider.ProxyIdAccessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.jpa.repository.sample.CategoryRepository;
import org.springframework.data.jpa.repository.sample.ProductRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
/**
* Integration tests for {@link PersistenceProvider}.
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class PersistenceProviderIntegrationTests {
@Configuration
@ImportResource("classpath:infrastructure.xml")
@EnableJpaRepositories(basePackageClasses = CategoryRepository.class,//
includeFilters = @Filter(value = { CategoryRepository.class, ProductRepository.class },
type = FilterType.ASSIGNABLE_TYPE))
static class Config {
}
@Autowired CategoryRepository categories;
@Autowired ProductRepository products;
@Autowired PlatformTransactionManager transactionManager;
@Autowired EntityManager em;
Product product;
Category category;
@Before
public void setUp() {
this.product = products.save(new Product());
this.category = categories.save(new Category(product));
}
/**
* @see DATAJPA-630
*/
@Test
public void testname() {
new TransactionTemplate(transactionManager).execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus status) {
Product product = categories.findOne(category.getId()).getProduct();
ProxyIdAccessor accessor = PersistenceProvider.fromEntityManager(em);
assertThat(accessor.shouldUseAccessorFor(product), is(true));
assertThat(accessor.getIdentifierFrom(product).toString(), is((Object) product.getId().toString()));
return null;
}
});
}
}

View File

@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.support;
package org.springframework.data.jpa.provider;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.jpa.provider.PersistenceProvider.*;
import static org.springframework.data.jpa.provider.PersistenceProvider.Constants.*;
import java.util.ArrayList;
import java.util.List;
@@ -28,6 +30,7 @@ import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.asm.ClassWriter;
import org.springframework.asm.Opcodes;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.instrument.classloading.ShadowingClassLoader;
import org.springframework.util.ClassUtils;
@@ -35,27 +38,28 @@ import org.springframework.util.ClassUtils;
* Tests for PersistenceProvider detection logic in {@link PersistenceProvider}.
*
* @author Thomas Darimont
* @author Oliver Gierke
*/
public class PersistenceProviderTests {
public class PersistenceProviderUnitTests {
private ShadowingClassLoader shadowingClassLoader;
ShadowingClassLoader shadowingClassLoader;
@Before
public void setup() {
shadowingClassLoader = new ShadowingClassLoader(getClass().getClassLoader());
this.shadowingClassLoader = new ShadowingClassLoader(getClass().getClassLoader());
}
/**
* @see DATAJPA-444
*/
@Test
public void detectsHibernatePersistenceProviderForHibernateVersionLessThan4dot3() throws Exception {
public void detectsHibernatePersistenceProviderForHibernateVersionLessThan4Dot3() throws Exception {
shadowingClassLoader.excludePackage("org.hibernate");
EntityManager em = mockProviderSpecificEntityManagerInterface(PersistenceProvider.Constants.HIBERNATE_ENTITY_MANAGER_INTERFACE);
EntityManager em = mockProviderSpecificEntityManagerInterface(HIBERNATE_ENTITY_MANAGER_INTERFACE);
assertThat(PersistenceProvider.fromEntityManager(em), is(PersistenceProvider.HIBERNATE));
assertThat(fromEntityManager(em), is(HIBERNATE));
}
/**
@@ -66,9 +70,9 @@ public class PersistenceProviderTests {
shadowingClassLoader.excludePackage("org.hibernate");
EntityManager em = mockProviderSpecificEntityManagerInterface(PersistenceProvider.Constants.HIBERNATE43_ENTITY_MANAGER_INTERFACE);
EntityManager em = mockProviderSpecificEntityManagerInterface(HIBERNATE43_ENTITY_MANAGER_INTERFACE);
assertThat(PersistenceProvider.fromEntityManager(em), is(PersistenceProvider.HIBERNATE));
assertThat(fromEntityManager(em), is(HIBERNATE));
}
@Test
@@ -76,9 +80,9 @@ public class PersistenceProviderTests {
shadowingClassLoader.excludePackage("org.apache.openjpa.persistence");
EntityManager em = mockProviderSpecificEntityManagerInterface(PersistenceProvider.Constants.OPENJPA_ENTITY_MANAGER_INTERFACE);
EntityManager em = mockProviderSpecificEntityManagerInterface(OPENJPA_ENTITY_MANAGER_INTERFACE);
assertThat(PersistenceProvider.fromEntityManager(em), is(PersistenceProvider.OPEN_JPA));
assertThat(fromEntityManager(em), is(OPEN_JPA));
}
@Test
@@ -86,9 +90,9 @@ public class PersistenceProviderTests {
shadowingClassLoader.excludePackage("org.eclipse.persistence.jpa");
EntityManager em = mockProviderSpecificEntityManagerInterface(PersistenceProvider.Constants.ECLIPSELINK_ENTITY_MANAGER_INTERFACE);
EntityManager em = mockProviderSpecificEntityManagerInterface(ECLIPSELINK_ENTITY_MANAGER_INTERFACE);
assertThat(PersistenceProvider.fromEntityManager(em), is(PersistenceProvider.ECLIPSELINK));
assertThat(fromEntityManager(em), is(ECLIPSELINK));
}
@Test
@@ -96,7 +100,7 @@ public class PersistenceProviderTests {
EntityManager em = mockProviderSpecificEntityManagerInterface("foo.bar.unknown.jpa.JpaEntityManager");
assertThat(PersistenceProvider.fromEntityManager(em), is(PersistenceProvider.GENERIC_JPA));
assertThat(fromEntityManager(em), is(GENERIC_JPA));
}
private EntityManager mockProviderSpecificEntityManagerInterface(String interfaceName) throws ClassNotFoundException {

View File

@@ -48,7 +48,7 @@ import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
* @author Thomas Darimont
*/
@RunWith(MockitoJUnitRunner.class)
public class CrudMethodMetadataIntegrationTests {
public class CrudMethodMetadataUnitTests {
@Mock EntityManager em;
@Mock EntityManagerFactory emf;
@@ -65,6 +65,7 @@ public class CrudMethodMetadataIntegrationTests {
when(information.getJavaType()).thenReturn(Role.class);
when(em.getDelegate()).thenReturn(em);
when(em.getEntityManagerFactory()).thenReturn(emf);
when(emf.createEntityManager()).thenReturn(em);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2014 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.
@@ -22,7 +22,6 @@ import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;

View File

@@ -34,11 +34,12 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.jpa.repository.support.PersistenceProvider;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.test.context.ContextConfiguration;

View File

@@ -35,6 +35,7 @@ import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.NamedQueries;

View File

@@ -36,6 +36,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
import org.springframework.data.jpa.repository.JpaRepository;

View File

@@ -30,6 +30,7 @@ import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryCreationException;

View File

@@ -42,8 +42,8 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.jpa.repository.Temporal;
import org.springframework.data.jpa.repository.support.PersistenceProvider;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import org.springframework.data.repository.query.Param;

View File

@@ -40,6 +40,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.sample.User;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.sample.UserRepository;
import org.springframework.data.repository.core.RepositoryMetadata;

View File

@@ -0,0 +1,24 @@
/*
* Copyright 2014 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.data.jpa.repository.sample;
import org.springframework.data.jpa.domain.sample.Category;
import org.springframework.data.repository.CrudRepository;
/**
* @author Oliver Gierke
*/
public interface CategoryRepository extends CrudRepository<Category, Long> {}

View File

@@ -0,0 +1,26 @@
/*
* Copyright 2014 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.data.jpa.repository.sample;
import org.springframework.data.jpa.domain.sample.Product;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author Oliver Gierke
*/
public interface ProductRepository extends JpaRepository<Product, Long> {
}

View File

@@ -38,7 +38,8 @@ public class EclipseLinkJpaMetamodelEntityInformationIntegrationTests extends
*/
@Test
public void reactivatedDetectsIdTypeForMappedSuperclass() {
JpaEntityInformation<?, ?> information = JpaEntityInformationSupport.getMetadata(AbstractPersistable.class, em);
JpaEntityInformation<?, ?> information = JpaEntityInformationSupport.getEntityInformation(
AbstractPersistable.class, em);
assertEquals(String.class, information.getIdType());
}
@@ -56,10 +57,6 @@ public class EclipseLinkJpaMetamodelEntityInformationIntegrationTests extends
@Ignore
public void detectsNewStateForEntityWithPrimitiveId() {}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformationIntegrationTests#considersEntityWithUnSetCompundIdNew()
*/
@Override
@Ignore
public void considersEntityWithUnsetCompundIdNew() {}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2014 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.data.jpa.repository.support;
import org.junit.Ignore;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.jpa.provider.PersistenceProviderIntegrationTests;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Oliver Gierke
*/
@ContextConfiguration(classes = EclipseLinkProxyIdAccessorTests.EclipseLinkConfig.class)
public class EclipseLinkProxyIdAccessorTests extends PersistenceProviderIntegrationTests {
@Configuration
@ImportResource("classpath:eclipselink.xml")
static class EclipseLinkConfig {}
/**
* Do not execute the test as EclipseLink does not create a lazy-loading proxy as expected.
*/
@Override
@Ignore
public void testname() {}
}

View File

@@ -61,7 +61,7 @@ public class JpaEntityInformationSupportUnitTests {
public void rejectsClassNotBeingFoundInMetamodel() {
when(em.getMetamodel()).thenReturn(metaModel);
JpaEntityInformationSupport.getMetadata(User.class, em);
JpaEntityInformationSupport.getEntityInformation(User.class, em);
}
static class User {

View File

@@ -17,6 +17,7 @@ package org.springframework.data.jpa.repository.support;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.*;
import java.io.Serializable;
import java.sql.Timestamp;
@@ -43,7 +44,6 @@ import org.springframework.data.jpa.domain.sample.PersistableWithIdClassPK;
import org.springframework.data.jpa.domain.sample.PrimitiveVersionProperty;
import org.springframework.data.jpa.domain.sample.Role;
import org.springframework.data.jpa.domain.sample.SampleWithIdClass;
import org.springframework.data.jpa.domain.sample.SampleWithIdClass.SampleWithIdClassPK;
import org.springframework.data.jpa.domain.sample.SampleWithPrimitiveId;
import org.springframework.data.jpa.domain.sample.SampleWithTimestampVersion;
import org.springframework.data.jpa.domain.sample.User;
@@ -68,7 +68,7 @@ public class JpaMetamodelEntityInformationIntegrationTests {
@Test
public void detectsIdTypeForEntity() {
JpaEntityInformation<User, ?> information = JpaEntityInformationSupport.getMetadata(User.class, em);
JpaEntityInformation<User, ?> information = getEntityInformation(User.class, em);
assertThat(information.getIdType(), is(typeCompatibleWith(Integer.class)));
}
@@ -83,7 +83,7 @@ public class JpaMetamodelEntityInformationIntegrationTests {
@Ignore
public void detectsIdTypeForMappedSuperclass() {
JpaEntityInformation<?, ?> information = JpaEntityInformationSupport.getMetadata(AbstractPersistable.class, em);
JpaEntityInformation<?, ?> information = getEntityInformation(AbstractPersistable.class, em);
assertEquals(Serializable.class, information.getIdType());
}
@@ -93,8 +93,7 @@ public class JpaMetamodelEntityInformationIntegrationTests {
@Test
public void detectsIdClass() {
EntityInformation<PersistableWithIdClass, ?> information = JpaEntityInformationSupport.getMetadata(
PersistableWithIdClass.class, em);
EntityInformation<PersistableWithIdClass, ?> information = getEntityInformation(PersistableWithIdClass.class, em);
assertThat(information.getIdType(), is(typeCompatibleWith(PersistableWithIdClassPK.class)));
}
@@ -106,8 +105,7 @@ public class JpaMetamodelEntityInformationIntegrationTests {
PersistableWithIdClass entity = new PersistableWithIdClass(2L, 4L);
JpaEntityInformation<PersistableWithIdClass, ?> information = JpaEntityInformationSupport.getMetadata(
PersistableWithIdClass.class, em);
JpaEntityInformation<PersistableWithIdClass, ?> information = getEntityInformation(PersistableWithIdClass.class, em);
Object id = information.getId(entity);
assertThat(id, is(instanceOf(PersistableWithIdClassPK.class)));
@@ -227,8 +225,7 @@ public class JpaMetamodelEntityInformationIntegrationTests {
@Test
public void considersEntityWithUnsetCompundIdNew() {
EntityInformation<SampleWithIdClass, SampleWithIdClassPK> information = new JpaMetamodelEntityInformation<SampleWithIdClass, SampleWithIdClassPK>(
SampleWithIdClass.class, em.getMetamodel());
EntityInformation<SampleWithIdClass, ?> information = getEntityInformation(SampleWithIdClass.class, em);
assertThat(information.isNew(new SampleWithIdClass()), is(true));
}
@@ -239,7 +236,8 @@ public class JpaMetamodelEntityInformationIntegrationTests {
@Test
public void considersEntityWithSetTimestampVersionNotNew() {
EntityInformation<SampleWithTimestampVersion, Long> information = getEntityInformation(SampleWithTimestampVersion.class);
EntityInformation<SampleWithTimestampVersion, ?> information = getEntityInformation(
SampleWithTimestampVersion.class, em);
SampleWithTimestampVersion entity = new SampleWithTimestampVersion();
entity.version = new Timestamp(new Date().getTime());
@@ -253,7 +251,7 @@ public class JpaMetamodelEntityInformationIntegrationTests {
@Test
public void considersEntityWithNonPrimitiveNonNullIdTypeNotNew() {
EntityInformation<User, Long> information = getEntityInformation(User.class);
EntityInformation<User, ?> information = getEntityInformation(User.class, em);
User user = new User();
assertThat(information.isNew(user), is(true));
@@ -262,10 +260,6 @@ public class JpaMetamodelEntityInformationIntegrationTests {
assertThat(information.isNew(user), is(false));
}
private <T, ID extends Serializable> EntityInformation<T, ID> getEntityInformation(Class<T> domainType) {
return new JpaMetamodelEntityInformation<T, ID>(domainType, em.getMetamodel());
}
protected String getMetadadataPersitenceUnitName() {
return "metadata";
}

View File

@@ -52,27 +52,27 @@ public class JpaRepositoryFactoryUnitTests {
JpaRepositoryFactory factory;
@Mock EntityManager entityManager;
@Mock @SuppressWarnings("rawtypes") JpaEntityInformation metadata;
@Mock @SuppressWarnings("rawtypes") JpaEntityInformation entityInformation;
@Mock EntityManagerFactory emf;
@Before
public void setUp() {
when(entityManager.getEntityManagerFactory()).thenReturn(emf);
when(entityManager.getDelegate()).thenReturn(entityManager);
when(emf.createEntityManager()).thenReturn(entityManager);
// Setup standard factory configuration
factory = new JpaRepositoryFactory(entityManager) {
@Override
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> JpaEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
return metadata;
return entityInformation;
};
};
factory.setQueryLookupStrategyKey(Key.CREATE_IF_NOT_FOUND);
when(entityManager.getEntityManagerFactory()).thenReturn(emf);
when(emf.createEntityManager()).thenReturn(entityManager);
}
/**
@@ -140,7 +140,7 @@ public class JpaRepositoryFactoryUnitTests {
@Test
public void usesQueryDslRepositoryIfInterfaceImplementsExecutor() {
when(metadata.getJavaType()).thenReturn(User.class);
when(entityInformation.getJavaType()).thenReturn(User.class);
assertEquals(QueryDslJpaRepository.class,
factory.getRepositoryBaseClass(new DefaultRepositoryMetadata(QueryDslSampleRepository.class)));

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2014 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.data.jpa.repository.support;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.jpa.provider.PersistenceProviderIntegrationTests;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Oliver Gierke
*/
@ContextConfiguration
public class OpenJpaProxyIdAccessorTests extends PersistenceProviderIntegrationTests {
@Configuration
@ImportResource("classpath:openjpa.xml")
static class Config {}
}

View File

@@ -53,6 +53,8 @@ public class SimpleJpaRepositoryUnitTests {
@Before
public void setUp() {
when(em.getDelegate()).thenReturn(em);
when(information.getJavaType()).thenReturn(User.class);
when(em.getCriteriaBuilder()).thenReturn(builder);

View File

@@ -10,6 +10,7 @@
<class>org.springframework.data.jpa.domain.sample.AnnotatedAuditableUser</class>
<class>org.springframework.data.jpa.domain.sample.AuditableRole</class>
<class>org.springframework.data.jpa.domain.sample.AuditableUser</class>
<class>org.springframework.data.jpa.domain.sample.Category</class>
<class>org.springframework.data.jpa.domain.sample.Child</class>
<class>org.springframework.data.jpa.domain.sample.ConcreteType1</class>
<class>org.springframework.data.jpa.domain.sample.ConcreteType2</class>
@@ -26,6 +27,7 @@
<class>org.springframework.data.jpa.domain.sample.Parent</class>
<class>org.springframework.data.jpa.domain.sample.PersistableWithIdClass</class>
<class>org.springframework.data.jpa.domain.sample.PrimitiveVersionProperty</class>
<class>org.springframework.data.jpa.domain.sample.Product</class>
<class>org.springframework.data.jpa.domain.sample.Role</class>
<class>org.springframework.data.jpa.domain.sample.SampleEntity</class>
<class>org.springframework.data.jpa.domain.sample.SampleEntityPK</class>

View File

@@ -6,24 +6,28 @@
<class>org.springframework.data.jpa.domain.sample.AnnotatedAuditableUser</class>
<class>org.springframework.data.jpa.domain.sample.AuditableRole</class>
<class>org.springframework.data.jpa.domain.sample.AuditableUser</class>
<class>org.springframework.data.jpa.domain.sample.User</class>
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
<class>org.springframework.data.jpa.domain.sample.Role</class>
<class>org.springframework.data.jpa.domain.sample.Category</class>
<class>org.springframework.data.jpa.domain.sample.MailMessage</class>
<class>org.springframework.data.jpa.domain.sample.MailSender</class>
<class>org.springframework.data.jpa.domain.sample.MailUser</class>
<class>org.springframework.data.jpa.domain.sample.Product</class>
<class>org.springframework.data.jpa.domain.sample.Role</class>
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
<class>org.springframework.data.jpa.domain.sample.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
<persistence-unit name="second">
<class>org.springframework.data.jpa.domain.sample.User</class>
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
<class>org.springframework.data.jpa.domain.sample.Role</class>
<class>org.springframework.data.jpa.domain.sample.AnnotatedAuditableUser</class>
<class>org.springframework.data.jpa.domain.sample.AuditableUser</class>
<class>org.springframework.data.jpa.domain.sample.AuditableRole</class>
<class>org.springframework.data.jpa.domain.sample.Category</class>
<class>org.springframework.data.jpa.domain.sample.MailMessage</class>
<class>org.springframework.data.jpa.domain.sample.MailSender</class>
<class>org.springframework.data.jpa.domain.sample.MailUser</class>
<class>org.springframework.data.jpa.domain.sample.Product</class>
<class>org.springframework.data.jpa.domain.sample.Role</class>
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
<class>org.springframework.data.jpa.domain.sample.User</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
</persistence-unit>
</persistence>

View File

@@ -12,7 +12,7 @@ Import-Template:
javax.annotation.*;version="0.0.0",
javax.enterprise.*;version="${cdi:[=.=.=,+1.0.0)}";resolution:=optional,
org.aopalliance.*;version="[1.0.0,2.0.0)",
org.apache.openjpa.persistence.*;version="${openjpa:[=.=.=,+1.0.0)}";resolution:=optional,
org.apache.openjpa.*;version="${openjpa:[=.=.=,+1.0.0)}";resolution:=optional,
org.aspectj.*;version="${aspectj:[=.=.=,+1.0.0)}";resolution:=optional,
org.eclipse.persistence.*;version="${eclipselink:[=.=.=,+1.0.0)}";resolution:=optional,
org.hibernate.*;version="[3.6.10,4.4.0)";resolution:=optional,