From 158ee85d93b88ceafba39c835c967d362b23da8e Mon Sep 17 00:00:00 2001 From: Jon Brisbin Date: Fri, 11 Mar 2011 14:15:00 -0600 Subject: [PATCH] Added mapping support to commons core. Will be used by other spring-data projects for multi-store mapping. --- .gitignore | 4 + spring-data-commons-core/pom.xml | 148 ++++++------ .../springframework/data/annotation/Id.java | 30 +++ .../annotation/PersistenceConstructor.java | 30 +++ .../data/annotation/Persistent.java | 35 +++ .../data/annotation/Reference.java | 33 +++ .../data/annotation/Transient.java | 30 +++ .../data/mapping/AssociationHandler.java | 27 +++ .../BasicMappingConfigurationBuilder.java | 212 ++++++++++++++++++ .../data/mapping/BasicMappingContext.java | 197 ++++++++++++++++ .../data/mapping/BasicPersistentEntity.java | 127 +++++++++++ .../data/mapping/BasicPersistentProperty.java | 149 ++++++++++++ .../data/mapping/MappingBeanHelper.java | 190 ++++++++++++++++ .../data/mapping/PropertyHandler.java | 26 +++ .../data/mapping/model/Association.java | 47 ++++ .../model/IllegalMappingException.java | 32 +++ .../model/MappingConfigurationBuilder.java | 43 ++++ .../model/MappingConfigurationException.java | 30 +++ .../data/mapping/model/MappingContext.java | 131 +++++++++++ .../data/mapping/model/MappingException.java | 30 +++ .../model/MappingInstantiationException.java | 30 +++ .../data/mapping/model/PersistentEntity.java | 87 +++++++ .../mapping/model/PersistentProperty.java | 52 +++++ .../mapping/model/PreferredConstructor.java | 90 ++++++++ .../springframework/data/mapping/Child.java | 31 +++ .../data/mapping/Document.java | 36 +++ .../data/mapping/MappingMetadataTests.java | 82 +++++++ .../springframework/data/mapping/Person.java | 58 +++++ .../data/mapping/PersonDocument.java | 29 +++ .../data/mapping/PersonNoId.java | 28 +++ .../data/mapping/PersonPersistent.java | 31 +++ .../data/mapping/PersonWithChildren.java | 43 ++++ .../data/mapping/PersonWithId.java | 37 +++ .../src/test/resources/log4j.xml | 22 ++ .../src/test/resources/mapping.xml | 7 + spring-data-commons-core/template.mf | 4 + 36 files changed, 2146 insertions(+), 72 deletions(-) create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/annotation/Id.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/annotation/PersistenceConstructor.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/annotation/Persistent.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/annotation/Reference.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/annotation/Transient.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/AssociationHandler.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingConfigurationBuilder.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingContext.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentEntity.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentProperty.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyHandler.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/Association.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/IllegalMappingException.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationBuilder.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationException.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingContext.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingException.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java create mode 100644 spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PreferredConstructor.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/Child.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/Document.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/Person.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonDocument.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonNoId.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonPersistent.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithChildren.java create mode 100644 spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithId.java create mode 100644 spring-data-commons-core/src/test/resources/log4j.xml create mode 100644 spring-data-commons-core/src/test/resources/mapping.xml diff --git a/.gitignore b/.gitignore index aee5425d5..11fa2c9b2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ target .springBeans .ant-targets-build.xml src/ant/.ant-targets-upload-dist.xml +.DS_Store +*.iml +*.ipr +*.iws diff --git a/spring-data-commons-core/pom.xml b/spring-data-commons-core/pom.xml index aff94706e..9614b8343 100644 --- a/spring-data-commons-core/pom.xml +++ b/spring-data-commons-core/pom.xml @@ -1,79 +1,83 @@ - 4.0.0 - - org.springframework.data - spring-data-commons-parent - 1.0.0.BUILD-SNAPSHOT - ../spring-data-commons-parent/pom.xml - - spring-data-commons-core - jar - Spring Data Commons Core - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + 4.0.0 + + org.springframework.data + spring-data-commons-parent + 1.0.0.BUILD-SNAPSHOT + ../spring-data-commons-parent/pom.xml + + spring-data-commons-core + jar + Spring Data Commons Core + - - - org.springframework - spring-beans - - - org.springframework - spring-tx - + + + org.springframework + spring-beans + + + org.springframework + spring-tx + - - - org.slf4j - slf4j-api - - - org.slf4j - jcl-over-slf4j - test - - - org.slf4j - slf4j-log4j12 - test - - - log4j - log4j - test - - - - javax.annotation - jsr250-api - true - + + + org.slf4j + slf4j-api + + + org.slf4j + jcl-over-slf4j + test + + + org.slf4j + slf4j-log4j12 + test + + + log4j + log4j + runtime + - - org.mockito - mockito-all - test - + + javax.annotation + jsr250-api + true + - - junit - junit - - - - joda-time - joda-time - 1.6 - true - + + org.mockito + mockito-all + test + - - - - - com.springsource.bundlor - com.springsource.bundlor.maven - - - + + junit + junit + + + org.springframework + spring-test + + + + joda-time + joda-time + 1.6 + true + + + + + + + com.springsource.bundlor + com.springsource.bundlor.maven + + + diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Id.java b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Id.java new file mode 100644 index 000000000..3a8decceb --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Id.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author J. Brisbin + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = {ElementType.FIELD}) +public @interface Id { +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/annotation/PersistenceConstructor.java b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/PersistenceConstructor.java new file mode 100644 index 000000000..d50acd0d2 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/PersistenceConstructor.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Jon Brisbin + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.CONSTRUCTOR) +public @interface PersistenceConstructor { +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Persistent.java b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Persistent.java new file mode 100644 index 000000000..c613148d7 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Persistent.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author J. Brisbin + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value = { + ElementType.TYPE, + ElementType.ANNOTATION_TYPE, + ElementType.FIELD, + ElementType.PARAMETER +}) +public @interface Persistent { +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Reference.java b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Reference.java new file mode 100644 index 000000000..e1adb0bfa --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Reference.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Jon Brisbin + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ + ElementType.ANNOTATION_TYPE, + ElementType.FIELD +}) +public @interface Reference { +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Transient.java b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Transient.java new file mode 100644 index 000000000..d2643445c --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/annotation/Transient.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author J. Brisbin + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Transient { +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AssociationHandler.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AssociationHandler.java new file mode 100644 index 000000000..433e7c69c --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/AssociationHandler.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.mapping.model.Association; +import org.springframework.data.mapping.model.PersistentProperty; + +/** + * @author Jon Brisbin + */ +public interface AssociationHandler { + void doWithAssociation(Association association); +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingConfigurationBuilder.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingConfigurationBuilder.java new file mode 100644 index 000000000..40f691aa9 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingConfigurationBuilder.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.LocalVariableTableParameterNameDiscoverer; +import org.springframework.data.annotation.*; +import org.springframework.data.mapping.model.*; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.reflect.*; +import java.math.BigInteger; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * @author Jon Brisbin + */ +public class BasicMappingConfigurationBuilder implements MappingConfigurationBuilder { + + protected static ConcurrentMap, BeanInfo> beanInfo = new ConcurrentHashMap, BeanInfo>(); + protected Logger log = LoggerFactory.getLogger(getClass()); + + protected MappingContext mappingContext; + + public BasicMappingConfigurationBuilder(MappingContext mappingContext) { + this.mappingContext = mappingContext; + } + + @Override + public boolean isPersistentEntity(Class type) { + if (type.isAnnotationPresent(Persistent.class)) { + return true; + } else { + for (Annotation annotation : type.getDeclaredAnnotations()) { + if (annotation.annotationType().isAnnotationPresent(Persistent.class)) { + return true; + } + } + for (Field field : type.getDeclaredFields()) { + if (field.isAnnotationPresent(Id.class)) { + return true; + } + } + } + return false; + } + + @SuppressWarnings({"unchecked"}) + @Override + public PersistentEntity createPersistentEntity(Class type) throws MappingConfigurationException { + return new BasicPersistentEntity(mappingContext, type); + } + + @Override + public boolean isPersistentProperty(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException { + if ("class".equals(field.getName()) || isTransient(field)) { + return false; + } + return true; + } + + @SuppressWarnings({"unchecked"}) + @Override + public PersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException { + return new BasicPersistentProperty(field.getName(), field.getType(), field, descriptor); + } + + @Override + public PersistentProperty getIdProperty(Class type) throws MappingConfigurationException { + for (Field field : type.getDeclaredFields()) { + if (isIdField(field)) { + return createPersistentProperty(field, null); + } + } + return null; + } + + @SuppressWarnings({"unchecked"}) + @Override + public PreferredConstructor getPreferredConstructor(Class type) throws MappingConfigurationException { + // Find the right constructor + PreferredConstructor preferredConstructor = null; + + for (Constructor constructor : type.getConstructors()) { + if (constructor.getParameterTypes().length != 0) { + // Non-no-arg constructor + if (null == preferredConstructor || constructor.isAnnotationPresent(PersistenceConstructor.class)) { + preferredConstructor = new PreferredConstructor((Constructor) constructor); + + String[] paramNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(constructor); + Type[] paramTypes = constructor.getGenericParameterTypes(); + + for (int i = 0; i < paramTypes.length; i++) { + Class targetType = Object.class; + if (paramTypes[i] instanceof ParameterizedType) { + ParameterizedType ptype = (ParameterizedType) paramTypes[i]; + Type[] types = ptype.getActualTypeArguments(); + if (types.length == 1) { + if (types[0] instanceof TypeVariable) { + // Placeholder type + targetType = Object.class; + } else { + targetType = (Class) types[0]; + } + } else { + targetType = (Class) ptype.getRawType(); + } + } else { + if (paramTypes[i] instanceof TypeVariable) { + Type[] bounds = ((TypeVariable) paramTypes[i]).getBounds(); + if (bounds.length > 0) { + targetType = (Class) bounds[0]; + } + } else if (paramTypes[i] instanceof Class) { + targetType = (Class) paramTypes[i]; + } + } + preferredConstructor.addParameter(paramNames[i], targetType, targetType.getDeclaredAnnotations()); + } + + if (constructor.isAnnotationPresent(PersistenceConstructor.class)) { + // We're done + break; + } + } + } + } + + return preferredConstructor; + } + + @Override + public boolean isAssociation(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException { + if (!isTransient(field)) { + if (field.isAnnotationPresent(Reference.class)) { + return true; + } + for (Annotation annotation : field.getDeclaredAnnotations()) { + if (annotation.annotationType().isAnnotationPresent(Reference.class)) { + return true; + } + } + } + return false; + } + + @Override + public Association createAssociation(PersistentProperty property) { + // Only support uni-directional associations in the Basic configuration + Association association = new Association(property, null); + property.setAssociation(association); + + return association; + } + + protected BeanInfo getBeanInfo(Class type) { + BeanInfo info = beanInfo.get(type); + if (null == info) { + try { + info = Introspector.getBeanInfo(type); + } catch (IntrospectionException e) { + throw new MappingException(e.getMessage(), e); + } + beanInfo.put(type, info); + } + return info; + } + + protected boolean isTransient(Field field) { + if (Modifier.isTransient(field.getModifiers()) + || null != field.getAnnotation(Transient.class) + || null != field.getAnnotation(Value.class)) { + return true; + } + return false; + } + + protected boolean isIdField(Field field) { + if (field.isAnnotationPresent(Id.class)) { + return true; + } + + if (field.getType() == String.class || field.getType() == BigInteger.class) { + if ("id".equals(field.getName()) || "_id".equals(field.getName())) { + return true; + } + } + + return false; + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingContext.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingContext.java new file mode 100644 index 000000000..70e3e9b8b --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicMappingContext.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterRegistry; +import org.springframework.core.convert.support.ConversionServiceFactory; +import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.data.mapping.model.*; +import org.springframework.util.Assert; +import org.springframework.validation.Validator; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentSkipListSet; + +/** + * @author Jon Brisbin + */ +public class BasicMappingContext implements MappingContext, InitializingBean { + + protected Logger log = LoggerFactory.getLogger(getClass()); + protected MappingConfigurationBuilder builder; + protected ConcurrentMap> persistentEntities = new ConcurrentHashMap>(); + protected ConcurrentMap, List> validators = new ConcurrentHashMap, List>(); + protected ConcurrentSkipListSet listeners = new ConcurrentSkipListSet(); + protected GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); + + public BasicMappingContext() { + builder = new BasicMappingConfigurationBuilder(this); + } + + public BasicMappingContext(MappingConfigurationBuilder builder) { + this.builder = builder; + } + + public BasicMappingContext(MappingConfigurationBuilder builder, GenericConversionService conversionService) { + this.builder = builder; + this.conversionService = conversionService; + } + + @Override + public Collection> getPersistentEntities() { + return persistentEntities.values(); + } + + @SuppressWarnings({"unchecked"}) + @Override + public PersistentEntity getPersistentEntity(Class type) { + return (PersistentEntity) persistentEntities.get(type.getName()); + } + + @Override + public PersistentEntity getPersistentEntity(String name) { + return persistentEntities.get(name); + } + + @Override + public PersistentEntity addPersistentEntity(Class type) { + if (null == persistentEntities.get(type.getName())) { + try { + PersistentEntity entity = builder.createPersistentEntity(type); + BeanInfo info = Introspector.getBeanInfo(type); + + Map descriptors = new HashMap(); + for (PropertyDescriptor descriptor : info.getPropertyDescriptors()) { + descriptors.put(descriptor.getName(), descriptor); + } + + for (Field field : type.getDeclaredFields()) { + PropertyDescriptor descriptor = descriptors.get(field.getName()); + if (builder.isPersistentProperty(field, descriptor)) { + PersistentProperty property = builder.createPersistentProperty(field, descriptor); + property.setOwner(entity); + entity.addPersistentProperty(property); + if (builder.isAssociation(field, descriptor)) { + Association association = builder.createAssociation(property); + entity.addAssociation(association); + } + } + } + + entity.setIdProperty(builder.getIdProperty(type)); + entity.setPreferredConstructor(builder.getPreferredConstructor(type)); + + // Inform listeners + List listenersToRemove = new ArrayList(); + for (Listener listener : listeners) { + if (!listener.persistentEntityAdded(entity)) { + listenersToRemove.add(listener); + } + } + for (Listener listener : listenersToRemove) { + listeners.remove(listener); + } + + persistentEntities.put(type.getName(), entity); + + return entity; + } catch (MappingConfigurationException e) { + log.error(e.getMessage(), e); + } catch (IntrospectionException e) { + throw new MappingException(e.getMessage(), e); + } + } + return null; + } + + @Override + public void addEntityValidator(PersistentEntity entity, Validator validator) { + List v = validators.get(entity); + if (null == v) { + v = new ArrayList(); + validators.put(entity, v); + } + v.add(validator); + } + + @Override + public void addTypeConverter(Converter converter) { + conversionService.addConverter(converter); + } + + @Override + public ConversionService getConversionService() { + return conversionService; + } + + @Override + public ConverterRegistry getConverterRegistry() { + return conversionService; + } + + @Override + public List getEntityValidators(PersistentEntity entity) { + return validators.get(entity); + } + + @Override + public MappingConfigurationBuilder getMappingConfigurationBuilder() { + return builder; + } + + @Override + public void setMappingConfigurationBuilder(MappingConfigurationBuilder builder) { + this.builder = builder; + } + + @SuppressWarnings({"unchecked"}) + @Override + public boolean isPersistentEntity(Object value) { + if (null != value) { + Class clazz; + if (value instanceof Class) { + clazz = ((Class) value); + } else { + clazz = value.getClass(); + } + return builder.isPersistentEntity(clazz); + } + return false; + } + + @Override + public void addContextListener(Listener listener) { + listeners.add(listener); + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.notNull(builder, "No mapping configuration provider configured."); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentEntity.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentEntity.java new file mode 100644 index 000000000..1e96400af --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentEntity.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.mapping.model.*; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Jon Brisbin + */ +public class BasicPersistentEntity implements PersistentEntity { + + protected final Class type; + protected PreferredConstructor preferredConstructor; + protected PersistentProperty idProperty; + protected Map> persistentProperties = new HashMap>(); + protected Map associations = new HashMap(); + + protected MappingContext mappingContext; + + public BasicPersistentEntity(MappingContext mappingContext, Class type) { + this.mappingContext = mappingContext; + this.type = type; + } + + @Override + public PreferredConstructor getPreferredConstructor() { + return preferredConstructor; + } + + @Override + public void setPreferredConstructor(PreferredConstructor constructor) { + this.preferredConstructor = constructor; + } + + @Override + public String getName() { + return type.getName(); + } + + @Override + public PersistentProperty getIdProperty() { + return idProperty; + } + + @Override + public void setIdProperty(PersistentProperty property) { + idProperty = property; + } + + @Override + public Collection> getPersistentProperties() { + return persistentProperties.values(); + } + + @Override + public void addPersistentProperty(PersistentProperty property) { + persistentProperties.put(property.getName(), property); + } + + @Override + public Collection getAssociations() { + return associations.values(); + } + + @Override + public void addAssociation(Association association) { + associations.put(association.getInverse().getName(), association); + } + + public PersistentProperty getPersistentProperty(String name) { + return persistentProperties.get(name); + } + + @Override + public Class getType() { + return type; + } + + @Override + public Collection getPersistentPropertyNames() { + return persistentProperties.keySet(); + } + + @Override + public MappingContext getMappingContext() { + return mappingContext; + } + + @Override + public void afterPropertiesSet() throws Exception { + + } + + @Override + public void doWithProperties(PropertyHandler handler) { + for (PersistentProperty property : persistentProperties.values()) { + if (!property.isTransient() && !property.isAssociation()) { + handler.doWithPersistentProperty(property); + } + } + } + + @Override + public void doWithAssociations(AssociationHandler handler) { + for (Association association : associations.values()) { + handler.doWithAssociation(association); + } + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentProperty.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentProperty.java new file mode 100644 index 000000000..a969c7d92 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/BasicPersistentProperty.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.annotation.Transient; +import org.springframework.data.mapping.model.Association; +import org.springframework.data.mapping.model.PersistentEntity; +import org.springframework.data.mapping.model.PersistentProperty; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; + +/** + * @author Jon Brisbin + */ +public class BasicPersistentProperty implements PersistentProperty { + + protected final String name; + protected final Class type; + protected final PropertyDescriptor propertyDescriptor; + protected final Field field; + protected Association association; + protected Value value; + protected boolean isTransient = false; + protected PersistentEntity owner; + + public BasicPersistentProperty(String name, + Class type, + Field field, + PropertyDescriptor propertyDescriptor) { + this.name = name; + this.type = type; + this.propertyDescriptor = propertyDescriptor; + this.field = field; + this.isTransient = Modifier.isTransient(field.getModifiers()) || field.isAnnotationPresent(Transient.class); + if (field.isAnnotationPresent(Value.class)) { + this.value = field.getAnnotation(Value.class); + // Fields with @Value annotations are considered the same as transient fields + this.isTransient = true; + } + if (field.isAnnotationPresent(Autowired.class)) { + this.isTransient = true; + } + } + + @Override + public Object getOwner() { + return owner; + } + + @Override + public void setOwner(Object owner) { + if (null != owner && owner.getClass().isAssignableFrom(PersistentEntity.class)) { + this.owner = (PersistentEntity) owner; + } + } + + @Override + public String getName() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public PropertyDescriptor getPropertyDescriptor() { + return propertyDescriptor; + } + + @Override + public Field getField() { + return field; + } + + @Override + public Value getValueAnnotation() { + return value; + } + + @Override + public boolean isTransient() { + return isTransient; + } + + @Override + public boolean isAssociation() { + return null != association; + } + + @Override + public Association getAssociation() { + return association; + } + + @Override + public void setAssociation(Association association) { + this.association = association; + } + + @Override + public boolean isCollection() { + return type.isAssignableFrom(Collection.class) || type.isAssignableFrom(List.class); + } + + @Override + public boolean isComplexType() { + return !MappingBeanHelper.getSimpleTypes().contains(field.getType().getName()); + } + + @Override + public Class getComponentType() { + if (isCollection()) { + Type genericType = field.getGenericType(); + if (genericType instanceof ParameterizedType) { + Type[] genericTypes = ((ParameterizedType) genericType).getActualTypeArguments(); + for (Type t : genericTypes) { + if (t instanceof Class) { + return (Class) t; + } + } + } + } + return type.getComponentType(); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java new file mode 100644 index 000000000..8836a704a --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/MappingBeanHelper.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.convert.support.ConversionServiceFactory; +import org.springframework.core.convert.support.GenericConversionService; +import org.springframework.data.mapping.model.MappingInstantiationException; +import org.springframework.data.mapping.model.PersistentEntity; +import org.springframework.data.mapping.model.PersistentProperty; +import org.springframework.data.mapping.model.PreferredConstructor; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +/** + * @author Jon Brisbin + */ +public abstract class MappingBeanHelper { + + protected static GenericConversionService conversionService = ConversionServiceFactory.createDefaultConversionService(); + protected static SpelExpressionParser parser = new SpelExpressionParser(); + protected static Set simpleTypes = new ConcurrentSkipListSet() {{ + add(boolean.class.getName()); + add(long.class.getName()); + add(short.class.getName()); + add(int.class.getName()); + add(byte.class.getName()); + add(float.class.getName()); + add(double.class.getName()); + add(char.class.getName()); + add(Boolean.class.getName()); + add(Long.class.getName()); + add(Short.class.getName()); + add(Integer.class.getName()); + add(Byte.class.getName()); + add(Float.class.getName()); + add(Double.class.getName()); + add(Character.class.getName()); + add(String.class.getName()); + add(java.util.Date.class.getName()); + add(Locale.class.getName()); + add(Class.class.getName()); + }}; + + public static GenericConversionService getConversionService() { + return conversionService; + } + + public static void setConversionService(GenericConversionService conversionService) { + MappingBeanHelper.conversionService = conversionService; + } + + public static Set getSimpleTypes() { + return simpleTypes; + } + + public static T constructInstance(PersistentEntity entity, + PreferredConstructor.ParameterValueProvider provider) { + return constructInstance(entity, provider, new StandardEvaluationContext()); + } + + public static T constructInstance(PersistentEntity entity, + PreferredConstructor.ParameterValueProvider provider, + EvaluationContext spelCtx) { + + PreferredConstructor constructor = entity.getPreferredConstructor(); + if (null == constructor) { + try { + return entity.getType().newInstance(); + } catch (InstantiationException e) { + throw new MappingInstantiationException(e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new MappingInstantiationException(e.getMessage(), e); + } + } + + List params = new LinkedList(); + if (null != provider && constructor.getParameters().size() > 0) { + for (PreferredConstructor.Parameter parameter : constructor.getParameters()) { + Value v = parameter.getValue(); + Object obj; + if (null != v) { + Expression x = parser.parseExpression(v.value()); + obj = x.getValue(spelCtx); + } else { + obj = provider.getParameterValue(parameter); + } + params.add(obj); + } + } + + T obj = null; + try { + obj = constructor.getConstructor().newInstance(params.toArray()); + } catch (InstantiationException e) { + throw new MappingInstantiationException(e.getMessage(), e); + } catch (IllegalAccessException e) { + throw new MappingInstantiationException(e.getMessage(), e); + } catch (InvocationTargetException e) { + throw new MappingInstantiationException(e.getMessage(), e); + } + + return obj; + } + + public static void setProperty(Object on, + PersistentProperty property, + Object value) + throws IllegalAccessException, InvocationTargetException { + setProperty(on, property, value, false); + } + + public static void setProperty(Object on, + PersistentProperty property, + Object value, + boolean fieldAccessOnly) + throws IllegalAccessException, InvocationTargetException { + + Field field = property.getField(); + if (fieldAccessOnly || (null == property.getPropertyDescriptor() || null == property.getPropertyDescriptor().getWriteMethod())) { + field.setAccessible(true); + if (null != value && value.getClass().isAssignableFrom(field.getType())) { + field.set(on, value); + } else { + field.set(on, conversionService.convert(value, field.getType())); + } + return; + } + + Method setter = property.getPropertyDescriptor().getWriteMethod(); + Class[] paramTypes = setter.getParameterTypes(); + if (null != value && paramTypes.length > 0 && !value.getClass().isAssignableFrom(paramTypes[0])) { + setter.invoke(on, conversionService.convert(value, paramTypes[0])); + } else { + setter.invoke(on, value); + } + } + + @SuppressWarnings({"unchecked"}) + public static T getProperty(Object from, + PersistentProperty property, + Class type, + boolean fieldAccessOnly) + throws IllegalAccessException, InvocationTargetException { + + Field field = property.getField(); + if (fieldAccessOnly || (null == property.getPropertyDescriptor() || null == property.getPropertyDescriptor().getReadMethod())) { + field.setAccessible(true); + Object obj = field.get(from); + if (null != obj && !obj.getClass().isAssignableFrom(type)) { + return conversionService.convert(obj, type); + } else { + return (T) obj; + } + } + + Object obj = property.getPropertyDescriptor().getReadMethod().invoke(from); + if (null != obj && !obj.getClass().isAssignableFrom(type)) { + return conversionService.convert(obj, type); + } else { + return (T) obj; + } + } + +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyHandler.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyHandler.java new file mode 100644 index 000000000..1ba044dfd --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/PropertyHandler.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.mapping.model.PersistentProperty; + +/** + * @author Jon Brisbin + */ +public interface PropertyHandler { + void doWithPersistentProperty(PersistentProperty persistentProperty); +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/Association.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/Association.java new file mode 100644 index 000000000..185924c1a --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/Association.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping.model; + +/** + * @author Jon Brisbin + */ +public class Association { + + protected PersistentProperty inverse; + protected PersistentProperty obverse; + + public Association(PersistentProperty inverse, PersistentProperty obverse) { + this.inverse = inverse; + this.obverse = obverse; + } + + public PersistentProperty getInverse() { + return inverse; + } + + public void setInverse(PersistentProperty inverse) { + this.inverse = inverse; + } + + public PersistentProperty getObverse() { + return obverse; + } + + public void setObverse(PersistentProperty obverse) { + this.obverse = obverse; + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/IllegalMappingException.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/IllegalMappingException.java new file mode 100644 index 000000000..e3094bc88 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/IllegalMappingException.java @@ -0,0 +1,32 @@ +/* Copyright (C) 2010 SpringSource + * + * 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.mapping.model; + +/** + * Thrown when an error occurs reading the mapping between object and datastore + * + * @author Graeme Rocher + * @since 1.0 + */ +public class IllegalMappingException extends RuntimeException { + + public IllegalMappingException(String s, Throwable throwable) { + super(s, throwable); + } + + public IllegalMappingException(String s) { + super(s); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationBuilder.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationBuilder.java new file mode 100644 index 000000000..a1278b570 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationBuilder.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping.model; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; + +/** + * @author Jon Brisbin + */ +public interface MappingConfigurationBuilder { + + boolean isPersistentEntity(Class clazz); + + PersistentEntity createPersistentEntity(Class clazz) throws MappingConfigurationException; + + boolean isPersistentProperty(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException; + + PersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException; + + PersistentProperty getIdProperty(Class clazz) throws MappingConfigurationException; + + PreferredConstructor getPreferredConstructor(Class clazz) throws MappingConfigurationException; + + boolean isAssociation(Field field, PropertyDescriptor descriptor) throws MappingConfigurationException; + + Association createAssociation(PersistentProperty property); + +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationException.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationException.java new file mode 100644 index 000000000..09273426f --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingConfigurationException.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping.model; + +/** + * @author Jon Brisbin + */ +public class MappingConfigurationException extends Throwable { + public MappingConfigurationException(String s) { + super(s); + } + + public MappingConfigurationException(String s, Throwable throwable) { + super(s, throwable); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingContext.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingContext.java new file mode 100644 index 000000000..0d49d5a89 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingContext.java @@ -0,0 +1,131 @@ +/* Copyright 2004-2005 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.mapping.model; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterRegistry; +import org.springframework.validation.Validator; + +import java.util.Collection; +import java.util.List; + +/** + *

This interface defines the overall context including all known + * PersistentEntity instances and methods to obtain instances on demand

+ *

+ *

This interface is used internally to establish associations + * between entities and also at runtime to obtain entities by name

+ *

+ *

The generic type parameters T & R are used to specify the + * mapped form of a class (example Table) and property (example Column) respectively.

+ *

+ * + * @author Graeme Rocher + * @since 1.0 + */ +public interface MappingContext extends InitializingBean { + + + /** + * Obtains a list of PersistentEntity instances + * + * @return A list of PersistentEntity instances + */ + Collection> getPersistentEntities(); + + /** + * Obtains a PersistentEntity by name + * + * @param name The name of the entity + * @return The entity or null + */ + PersistentEntity getPersistentEntity(String name); + + PersistentEntity getPersistentEntity(Class type); + + /** + * Adds a PersistentEntity instance + * + * @param type The Java class representing the entity + * @return The PersistentEntity instance + */ + PersistentEntity addPersistentEntity(Class type); + + /** + * Adds a validator to be used by the entity for validation + * + * @param entity The PersistentEntity + * @param validator The validator + */ + void addEntityValidator(PersistentEntity entity, Validator validator); + + /** + * Add a converter used to convert property values to and from the datastore + * + * @param converter The converter to add + */ + void addTypeConverter(Converter converter); + + /** + * Obtains the ConversionService instance to use for type conversion + * + * @return The conversion service instance + */ + ConversionService getConversionService(); + + /** + * Obtains the converter registry + * + * @return The converter registry used for type conversion + */ + ConverterRegistry getConverterRegistry(); + + /** + * Obtains a validator for the given entity + * + * @param entity The entity + * @return A validator or null if none exists for the given entity + */ + List getEntityValidators(PersistentEntity entity); + + MappingConfigurationBuilder getMappingConfigurationBuilder(); + + void setMappingConfigurationBuilder(MappingConfigurationBuilder builder); + + /** + * Returns whether the specified value is a persistent entity + * + * @param value The value to check + * @return True if it is + */ + boolean isPersistentEntity(Object value); + + void addContextListener(Listener listener); + + /** + * Listener interface to deal with newly-added persistent entities. + */ + public interface Listener { + /** + * Handle this new entity, return true or false, depending on whether this listener should continue listening. + * + * @param entity + * @return 'true' to leave listener attached, 'false' to remove this listener + */ + boolean persistentEntityAdded(PersistentEntity entity); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingException.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingException.java new file mode 100644 index 000000000..20cb6864a --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingException.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping.model; + +/** + * @author Jon Brisbin + */ +public class MappingException extends RuntimeException { + public MappingException(String s) { + super(s); + } + + public MappingException(String s, Throwable throwable) { + super(s, throwable); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java new file mode 100644 index 000000000..6b208cc7c --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/MappingInstantiationException.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping.model; + +/** + * Created by IntelliJ IDEA. + * User: jbrisbin + * Date: 2/25/11 + * Time: 9:07 AM + * To change this template use File | Settings | File Templates. + */ +public class MappingInstantiationException extends RuntimeException { + public MappingInstantiationException(String s, Throwable throwable) { + super(s, throwable); + } +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java new file mode 100644 index 000000000..97dc0ab13 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentEntity.java @@ -0,0 +1,87 @@ +package org.springframework.data.mapping.model; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.mapping.AssociationHandler; +import org.springframework.data.mapping.PropertyHandler; + +import java.util.Collection; + + +/** + * Represents a persistent entity + * + * @author Graeme Rocher + * @since 1.0 + */ +public interface PersistentEntity extends InitializingBean { + + /** + * The entity name including any package prefix + * + * @return The entity name + */ + String getName(); + + PreferredConstructor getPreferredConstructor(); + + void setPreferredConstructor(PreferredConstructor constructor); + + /** + * Returns the identity of the instance + * + * @return The identity + */ + PersistentProperty getIdProperty(); + + void setIdProperty(PersistentProperty property); + + /** + * A list of properties to be persisted + * + * @return A list of PersistentProperty instances + */ + Collection> getPersistentProperties(); + + void addPersistentProperty(PersistentProperty property); + + /** + * A list of the associations for this entity. This is typically a subset of the list returned by {@link #getPersistentProperties()} + * + * @return A list of associations + */ + Collection getAssociations(); + + void addAssociation(Association association); + + /** + * Obtains a PersistentProperty instance by name + * + * @param name The name of the property + * @return The PersistentProperty or null if it doesn't exist + */ + PersistentProperty getPersistentProperty(String name); + + /** + * @return The underlying Java class for this entity + */ + Class getType(); + + /** + * A list of property names + * + * @return A List of strings + */ + Collection getPersistentPropertyNames(); + + /** + * Obtains the MappingContext where this PersistentEntity is defined + * + * @return The MappingContext instance + */ + MappingContext getMappingContext(); + + void doWithProperties(PropertyHandler handler); + + void doWithAssociations(AssociationHandler handler); + +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java new file mode 100644 index 000000000..500f33a31 --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PersistentProperty.java @@ -0,0 +1,52 @@ +package org.springframework.data.mapping.model; + +import org.springframework.beans.factory.annotation.Value; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; + +/** + * @author Graeme Rocher + * @since 1.0 + */ +public interface PersistentProperty { + + Object getOwner(); + + void setOwner(Object owner); + + /** + * The name of the property + * + * @return The property name + */ + String getName(); + + /** + * The type of the property + * + * @return The property type + */ + Class getType(); + + PropertyDescriptor getPropertyDescriptor(); + + Field getField(); + + Value getValueAnnotation(); + + boolean isTransient(); + + boolean isAssociation(); + + Association getAssociation(); + + void setAssociation(Association association); + + boolean isCollection(); + + boolean isComplexType(); + + Class getComponentType(); + +} diff --git a/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PreferredConstructor.java b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PreferredConstructor.java new file mode 100644 index 000000000..d66c6ee2f --- /dev/null +++ b/spring-data-commons-core/src/main/java/org/springframework/data/mapping/model/PreferredConstructor.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping.model; + +import org.springframework.beans.factory.annotation.Value; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.util.LinkedList; +import java.util.List; + +/** + * @author Jon Brisbin + */ +public class PreferredConstructor { + + protected Constructor constructor; + protected List parameters = new LinkedList(); + + public PreferredConstructor(Constructor constructor) { + this.constructor = constructor; + this.parameters = parameters; + } + + public Constructor getConstructor() { + return constructor; + } + + public List getParameters() { + return parameters; + } + + public void addParameter(String name, Class type, Annotation[] annotations) { + parameters.add(new Parameter(name, type, annotations)); + } + + public static class Parameter { + protected final String name; + protected final Class type; + protected final Annotation[] annotations; + protected Value value; + + public Parameter(String name, Class type, Annotation[] annotations) { + this.name = name; + this.type = type; + this.annotations = annotations; + for (Annotation anno : annotations) { + if (anno.annotationType() == Value.class) { + this.value = (Value) anno; + break; + } + } + } + + public String getName() { + return name; + } + + public Class getType() { + return type; + } + + public Annotation[] getAnnotations() { + return annotations; + } + + public Value getValue() { + return value; + } + } + + public static interface ParameterValueProvider { + Object getParameterValue(Parameter parameter); + } + +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Child.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Child.java new file mode 100644 index 000000000..000c13bdc --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Child.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.annotation.Persistent; + +/** + * @author Jon Brisbin + */ +@Persistent +public class Child extends PersonWithId { + + public Child(Integer ssn, String firstName, String lastName) { + super(ssn, firstName, lastName); + } + +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Document.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Document.java new file mode 100644 index 000000000..1810d4407 --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Document.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.annotation.Persistent; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Jon Brisbin + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ + ElementType.TYPE, + ElementType.FIELD +}) +@Persistent +public @interface Document { +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java new file mode 100644 index 000000000..5f736180a --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/MappingMetadataTests.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.data.mapping.model.Association; +import org.springframework.data.mapping.model.PersistentEntity; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import static junit.framework.Assert.*; + +/** + * @author Jon Brisbin + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:mapping.xml") +public class MappingMetadataTests { + + BasicMappingContext ctx; + + @Before + public void setup() { + ctx = new BasicMappingContext(); + } + + @Test + public void testDoesRecognizePersistentEntities() { + boolean persistentEntity = ctx.isPersistentEntity(PersonNoId.class); + assertFalse(persistentEntity); + + persistentEntity = ctx.isPersistentEntity(PersonPersistent.class); + assertTrue(persistentEntity); + } + + @Test + public void testPojoWithId() { + PersistentEntity person = ctx.addPersistentEntity(PersonWithId.class); + assertNotNull(person.getIdProperty()); + assertEquals(String.class, person.getIdProperty().getType()); + } + + @Test + public void testPojoWithoutId() { + PersistentEntity person = ctx.addPersistentEntity(PersonNoId.class); + assertNull(person.getIdProperty()); + } + + @Test + public void testAssociations() { + PersistentEntity person = ctx.addPersistentEntity(PersonWithChildren.class); + assertNotNull(person.getAssociations()); + + for (Association association : person.getAssociations()) { + assertEquals(Child.class, association.getInverse().getComponentType()); + } + } + + @Test + public void testDoesRecognizeDocumentEntities() { + // PersistentEntity person = ctx.addPersistentEntity(PersonDocument.class); + boolean persistentEntity = ctx.isPersistentEntity(PersonDocument.class); + assertTrue(persistentEntity); + } + +} \ No newline at end of file diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Person.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Person.java new file mode 100644 index 000000000..404536d5b --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/Person.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +/** + * @author Jon Brisbin + */ +public abstract class Person { + + private Integer ssn; + private String firstName; + private String lastName; + + protected Person(Integer ssn, String firstName, String lastName) { + this.ssn = ssn; + this.firstName = firstName; + this.lastName = lastName; + } + + public Integer getSsn() { + return ssn; + } + + public void setSsn(Integer ssn) { + this.ssn = ssn; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonDocument.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonDocument.java new file mode 100644 index 000000000..e8b0b0a4d --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonDocument.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +/** + * @author Jon Brisbin + */ +@Document +public class PersonDocument extends Person { + + public PersonDocument(Integer ssn, String firstName, String lastName) { + super(ssn, firstName, lastName); + } + +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonNoId.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonNoId.java new file mode 100644 index 000000000..d193b4fcc --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonNoId.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +/** + * @author Jon Brisbin + */ +public class PersonNoId extends Person { + + public PersonNoId(Integer ssn, String firstName, String lastName) { + super(ssn, firstName, lastName); + } + +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonPersistent.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonPersistent.java new file mode 100644 index 000000000..992ee0f04 --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonPersistent.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.annotation.Persistent; + +/** + * @author Jon Brisbin + */ +@Persistent +public class PersonPersistent extends PersonWithId { + + public PersonPersistent(Integer ssn, String firstName, String lastName) { + super(ssn, firstName, lastName); + } + +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithChildren.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithChildren.java new file mode 100644 index 000000000..b3cb4481f --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithChildren.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.annotation.Reference; + +import java.util.List; + +/** + * @author Jon Brisbin + */ +public class PersonWithChildren extends Person { + + @Reference + private List children; + + public PersonWithChildren(Integer ssn, String firstName, String lastName) { + super(ssn, firstName, lastName); + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + +} diff --git a/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithId.java b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithId.java new file mode 100644 index 000000000..8fa88a5df --- /dev/null +++ b/spring-data-commons-core/src/test/java/org/springframework/data/mapping/PersonWithId.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2011 by the original author(s). + * + * 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.mapping; + +import org.springframework.data.annotation.Id; + +/** + * @author Jon Brisbin + */ +public class PersonWithId extends Person { + + @Id + private String id; + + public PersonWithId(Integer ssn, String firstName, String lastName) { + super(ssn, firstName, lastName); + } + + public String getId() { + return id; + } + +} diff --git a/spring-data-commons-core/src/test/resources/log4j.xml b/spring-data-commons-core/src/test/resources/log4j.xml new file mode 100644 index 000000000..721aa73b8 --- /dev/null +++ b/spring-data-commons-core/src/test/resources/log4j.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-commons-core/src/test/resources/mapping.xml b/spring-data-commons-core/src/test/resources/mapping.xml new file mode 100644 index 000000000..30d582a9b --- /dev/null +++ b/spring-data-commons-core/src/test/resources/mapping.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/spring-data-commons-core/template.mf b/spring-data-commons-core/template.mf index af09e6b73..6f1dcb8fe 100644 --- a/spring-data-commons-core/template.mf +++ b/spring-data-commons-core/template.mf @@ -11,7 +11,11 @@ Import-Template: org.springframework.context.*;version="[3.0.0, 4.0.0)", org.springframework.dao.*;version="[3.0.0, 4.0.0)", org.springframework.util.*;version="[3.0.0, 4.0.0)", + org.springframework.expression.*;version="[3.0.0, 4.0.0)", + org.springframework.expression.spel.standard.*;version="[3.0.0, 4.0.0)", + org.springframework.expression.spel.support.*;version="[3.0.0, 4.0.0)", org.springframework.transaction.*;version="[3.0.0, 4.0.0)", + org.springframework.validation.*;version="[3.0.0, 4.0.0)", org.springframework.data.core.*;version="[1.0.0, 2.0.0)", org.springframework.data.persistence.*;version="[1.0.0, 2.0.0)", org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,