DATAJPA-274 - Introduce JPA Metamodel based MappingContext implementation.
Implemented rudimentary MappingContext to expose a JpaPersistentEntity through RepositoryFactoryInformation.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2012 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.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.springframework.data.mapping.context.AbstractMappingContext;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link MappingContext} implementation based on a Jpa {@link Metamodel}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
*/
|
||||
public class JpaMetamodelMappingContext extends
|
||||
AbstractMappingContext<JpaPersistentEntityImpl<?>, JpaPersistentProperty> {
|
||||
|
||||
private final Metamodel model;
|
||||
|
||||
/**
|
||||
* Creates a new JPA {@link Metamodel} based {@link MappingContext}.
|
||||
*
|
||||
* @param model must not be {@literal null}.
|
||||
*/
|
||||
public JpaMetamodelMappingContext(Metamodel model) {
|
||||
|
||||
Assert.notNull(model, "JPA Metamodel must not be null!");
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentEntity(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
protected <T> JpaPersistentEntityImpl<?> createPersistentEntity(TypeInformation<T> typeInformation) {
|
||||
return new JpaPersistentEntityImpl<T>(typeInformation, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.AbstractMappingContext#createPersistentProperty(java.lang.reflect.Field, java.beans.PropertyDescriptor, org.springframework.data.mapping.model.MutablePersistentEntity, org.springframework.data.mapping.model.SimpleTypeHolder)
|
||||
*/
|
||||
@Override
|
||||
protected JpaPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
|
||||
JpaPersistentEntityImpl<?> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
return new JpaPersistentPropertyImpl(model, field, descriptor, owner, simpleTypeHolder);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.context.AbstractMappingContext#shouldCreatePersistentEntityFor(org.springframework.data.util.TypeInformation)
|
||||
*/
|
||||
@Override
|
||||
protected boolean shouldCreatePersistentEntityFor(TypeInformation<?> type) {
|
||||
|
||||
try {
|
||||
model.managedType(type.getType());
|
||||
return true;
|
||||
} catch (IllegalArgumentException o_O) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012 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.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
|
||||
/**
|
||||
* Interface for a JPA-specific entity.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
*/
|
||||
public interface JpaPersistentEntity<T> extends PersistentEntity<T, JpaPersistentProperty> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2012 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.mapping;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
|
||||
/**
|
||||
* Implementation of {@link JpaPersistentEntity}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
*/
|
||||
class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentProperty> implements
|
||||
JpaPersistentEntity<T> {
|
||||
|
||||
/**
|
||||
* 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}.
|
||||
*/
|
||||
public JpaPersistentEntityImpl(TypeInformation<T> information, Comparator<JpaPersistentProperty> comparator) {
|
||||
super(information, comparator);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012 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.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
|
||||
/**
|
||||
* Interface for a JPA-specific {@link PersistentProperty}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
*/
|
||||
public interface JpaPersistentProperty extends PersistentProperty<JpaPersistentProperty> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2012 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.mapping;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToMany;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.metamodel.EmbeddableType;
|
||||
import javax.persistence.metamodel.ManagedType;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
|
||||
/**
|
||||
* {@link JpaPersistentProperty} implementation usind a JPA {@link Metamodel}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
*/
|
||||
class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPersistentProperty> implements
|
||||
JpaPersistentProperty {
|
||||
|
||||
private static final Collection<Class<? extends Annotation>> ASSOCIATION_ANNOTATIONS;
|
||||
private static final Collection<Class<? extends Annotation>> ID_ANNOTATIONS;
|
||||
|
||||
static {
|
||||
|
||||
Set<Class<? extends Annotation>> annotations = new HashSet<Class<? extends Annotation>>();
|
||||
annotations.add(OneToMany.class);
|
||||
annotations.add(ManyToMany.class);
|
||||
annotations.add(ManyToOne.class);
|
||||
|
||||
ASSOCIATION_ANNOTATIONS = Collections.unmodifiableSet(annotations);
|
||||
|
||||
annotations = new HashSet<Class<? extends Annotation>>();
|
||||
annotations.add(Id.class);
|
||||
annotations.add(EmbeddedId.class);
|
||||
|
||||
ID_ANNOTATIONS = annotations;
|
||||
}
|
||||
|
||||
private final Metamodel metamodel;
|
||||
|
||||
/**
|
||||
* Creates a new {@link JpaPersistentPropertyImpl}
|
||||
*
|
||||
* @param metamodel must not be {@literal null}.
|
||||
* @param field must not be {@literal null}.
|
||||
* @param propertyDescriptor can be {@literal null}.
|
||||
* @param owner must not be {@literal null}.
|
||||
* @param simpleTypeHolder must not be {@literal null}.
|
||||
*/
|
||||
public JpaPersistentPropertyImpl(Metamodel metamodel, Field field, PropertyDescriptor propertyDescriptor,
|
||||
PersistentEntity<?, JpaPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(field, propertyDescriptor, owner, simpleTypeHolder);
|
||||
this.metamodel = metamodel;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#isIdProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isIdProperty() {
|
||||
|
||||
for (Class<? extends Annotation> annotation : ID_ANNOTATIONS) {
|
||||
if (field.getAnnotation(annotation) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#isEntity()
|
||||
*/
|
||||
@Override
|
||||
public boolean isEntity() {
|
||||
|
||||
try {
|
||||
ManagedType<?> type = metamodel.managedType(getType());
|
||||
return !(type instanceof EmbeddableType);
|
||||
} catch (IllegalArgumentException o_O) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AnnotationBasedPersistentProperty#isAssociation()
|
||||
*/
|
||||
@Override
|
||||
public boolean isAssociation() {
|
||||
|
||||
for (Class<? extends Annotation> annotationType : ASSOCIATION_ANNOTATIONS) {
|
||||
if (field.getAnnotation(annotationType) != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#createAssociation()
|
||||
*/
|
||||
@Override
|
||||
protected Association<JpaPersistentProperty> createAssociation() {
|
||||
return new Association<JpaPersistentProperty>(this, null);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2011 the original author or authors.
|
||||
* Copyright 2008-2012 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.
|
||||
@@ -50,6 +50,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
|
||||
public JpaRepositoryFactory(EntityManager entityManager) {
|
||||
|
||||
Assert.notNull(entityManager);
|
||||
|
||||
this.entityManager = entityManager;
|
||||
this.extractor = PersistenceProvider.fromEntityManager(entityManager);
|
||||
this.lockModePostProcessor = LockModeRepositoryPostProcessor.INSTANCE;
|
||||
@@ -59,14 +60,10 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.data.repository.support.RepositoryFactorySupport#
|
||||
* getTargetRepository(java.lang.Class)
|
||||
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryMetadata)
|
||||
*/
|
||||
@Override
|
||||
protected Object getTargetRepository(RepositoryMetadata metadata) {
|
||||
|
||||
return getTargetRepository(metadata, entityManager);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.io.Serializable;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
|
||||
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
|
||||
@@ -45,8 +46,8 @@ public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends
|
||||
*/
|
||||
@PersistenceContext
|
||||
public void setEntityManager(EntityManager entityManager) {
|
||||
|
||||
this.entityManager = entityManager;
|
||||
setMappingContext(new JpaMetamodelMappingContext(entityManager.getMetamodel()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2012 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.mapping;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.data.jpa.domain.sample.User;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link JpaMetamodelMappingContext}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 1.3
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:infrastructure.xml")
|
||||
public class JpaMetamodelMappingContextIntegrationTests {
|
||||
|
||||
JpaMetamodelMappingContext context;
|
||||
|
||||
@PersistenceContext
|
||||
EntityManager em;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
context = new JpaMetamodelMappingContext(em.getMetamodel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setsUpMappingContextCorrectly() {
|
||||
|
||||
JpaPersistentEntityImpl<?> entity = context.getPersistentEntity(User.class);
|
||||
assertThat(entity, is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsIdProperty() {
|
||||
|
||||
JpaPersistentEntityImpl<?> entity = context.getPersistentEntity(User.class);
|
||||
assertThat(entity.getIdProperty(), is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsAssociation() {
|
||||
|
||||
JpaPersistentEntityImpl<?> entity = context.getPersistentEntity(User.class);
|
||||
assertThat(entity, is(notNullValue()));
|
||||
|
||||
JpaPersistentProperty property = entity.getPersistentProperty("manager");
|
||||
assertThat(property.isAssociation(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsPropertyIsEntity() {
|
||||
|
||||
JpaPersistentEntityImpl<?> entity = context.getPersistentEntity(User.class);
|
||||
assertThat(entity, is(notNullValue()));
|
||||
|
||||
JpaPersistentProperty property = entity.getPersistentProperty("manager");
|
||||
assertThat(property.isEntity(), is(true));
|
||||
|
||||
property = entity.getPersistentProperty("lastname");
|
||||
assertThat(property.isEntity(), is(false));
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -60,6 +61,8 @@ public class JpaRepositoryFactoryBeanUnitTests {
|
||||
PersistenceExceptionTranslator translator;
|
||||
@Mock
|
||||
Repository<?, ?> repository;
|
||||
@Mock
|
||||
Metamodel metamodel;
|
||||
|
||||
@Before
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -70,6 +73,7 @@ public class JpaRepositoryFactoryBeanUnitTests {
|
||||
when(beanFactory.getBeansOfType(eq(PersistenceExceptionTranslator.class), anyBoolean(), anyBoolean())).thenReturn(
|
||||
beans);
|
||||
when(factory.getRepository(any(Class.class), any(Object.class))).thenReturn(repository);
|
||||
when(entityManager.getMetamodel()).thenReturn(metamodel);
|
||||
|
||||
// Setup standard factory configuration
|
||||
factoryBean = new DummyJpaRepositoryFactoryBean<SimpleSampleRepository, User, Integer>();
|
||||
|
||||
Reference in New Issue
Block a user