diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java index d9c52e3bb..b7a6a1fa6 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/AbstractMongoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 the original author or authors. + * Copyright 2011-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,7 +37,9 @@ import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.mapping.CamelCaseAbbreviatingFieldNamingStrategy; import org.springframework.data.mongodb.core.mapping.Document; +import org.springframework.data.mongodb.core.mapping.FieldNamingStrategy; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; +import org.springframework.data.mongodb.core.mapping.PropertyNameFieldNamingStrategy; import org.springframework.data.support.CachingIsNewStrategyFactory; import org.springframework.data.support.IsNewStrategyFactory; import org.springframework.util.ClassUtils; @@ -51,6 +53,7 @@ import com.mongodb.Mongo; * @author Mark Pollack * @author Oliver Gierke * @author Thomas Darimont + * @author Ryan Tenney */ @Configuration public abstract class AbstractMongoConfiguration { @@ -144,10 +147,7 @@ public abstract class AbstractMongoConfiguration { MongoMappingContext mappingContext = new MongoMappingContext(); mappingContext.setInitialEntitySet(getInitialEntitySet()); mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder()); - - if (abbreviateFieldNames()) { - mappingContext.setFieldNamingStrategy(new CamelCaseAbbreviatingFieldNamingStrategy()); - } + mappingContext.setFieldNamingStrategy(fieldNamingStrategy()); return mappingContext; } @@ -232,4 +232,14 @@ public abstract class AbstractMongoConfiguration { protected boolean abbreviateFieldNames() { return false; } + + /** + * Configures a {@link FieldNamingStrategy} on the {@link MongoMappingContext} instance created. + * + * @return + */ + protected FieldNamingStrategy fieldNamingStrategy() { + return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy() + : PropertyNameFieldNamingStrategy.INSTANCE; + } } diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java index 6b601c66d..ef502f684 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/config/MappingMongoConverterParser.java @@ -210,11 +210,18 @@ public class MappingMongoConverterParser implements BeanDefinitionParser { } String abbreviateFieldNames = element.getAttribute("abbreviate-field-names"); + if ("true".equals(abbreviateFieldNames)) { mappingContextBuilder.addPropertyValue("fieldNamingStrategy", new RootBeanDefinition( CamelCaseAbbreviatingFieldNamingStrategy.class)); } + String fieldNamingStrategy = element.getAttribute("field-naming-strategy-ref"); + + if (StringUtils.hasText(fieldNamingStrategy)) { + mappingContextBuilder.addPropertyValue("fieldNamingStrategy", new RuntimeBeanReference(fieldNamingStrategy)); + } + ctxRef = converterId == null || DEFAULT_CONVERTER_BEAN_NAME.equals(converterId) ? MAPPING_CONTEXT_BEAN_NAME : converterId + "." + MAPPING_CONTEXT_BEAN_NAME; diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldNamingStrategy.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldNamingStrategy.java index 8d6deb88a..e8ffe3945 100644 --- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldNamingStrategy.java +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/FieldNamingStrategy.java @@ -21,6 +21,7 @@ package org.springframework.data.mongodb.core.mapping; * @see DocumentField * @see PropertyNameFieldNamingStrategy * @see CamelCaseAbbreviatingFieldNamingStrategy + * @see LowerCaseWithUnderscoresFieldNamingStrategy * @since 1.3 * @author Oliver Gierke */ diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/LowerCaseWithUnderscoresFieldNamingStrategy.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/LowerCaseWithUnderscoresFieldNamingStrategy.java new file mode 100644 index 000000000..59301d1d4 --- /dev/null +++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/mapping/LowerCaseWithUnderscoresFieldNamingStrategy.java @@ -0,0 +1,62 @@ +/* + * Copyright 2013 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.mongodb.core.mapping; + +/** + * {@link FieldNamingStrategy} that translates typical camel case Java + * property names to lower case JSON element names, separated by + * underscores. + * + * Source: jackson-databind, Apache 2 License + * https://github.com/FasterXML/jackson-databind/blob/2.3/src/main/java/com/fasterxml/jackson/databind/PropertyNamingStrategy.java + * + * @since 1.5 + * @author Ryan Tenney + */ +public class LowerCaseWithUnderscoresFieldNamingStrategy implements FieldNamingStrategy { + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.mapping.FieldNamingStrategy#getFieldName(org.springframework.data.mongodb.core.mapping.MongoPersistentProperty) + */ + public String getFieldName(MongoPersistentProperty property) { + String input = property.getName(); + int length = input.length(); + StringBuilder result = new StringBuilder(length * 2); + int resultLength = 0; + boolean wasPrevTranslated = false; + for (int i = 0; i < length; i++) { + char c = input.charAt(i); + if (i > 0 || c != '_') { // skip first starting underscore + if (Character.isUpperCase(c)) { + if (!wasPrevTranslated && resultLength > 0 && result.charAt(resultLength - 1) != '_') { + result.append('_'); + resultLength++; + } + c = Character.toLowerCase(c); + wasPrevTranslated = true; + } + else { + wasPrevTranslated = false; + } + result.append(c); + resultLength++; + } + } + return resultLength > 0 ? result.toString() : input; + } + +} diff --git a/spring-data-mongodb/src/main/resources/META-INF/spring.schemas b/spring-data-mongodb/src/main/resources/META-INF/spring.schemas index c5555508e..10b176c4d 100644 --- a/spring-data-mongodb/src/main/resources/META-INF/spring.schemas +++ b/spring-data-mongodb/src/main/resources/META-INF/spring.schemas @@ -3,4 +3,5 @@ http\://www.springframework.org/schema/data/mongo/spring-mongo-1.1.xsd=org/sprin http\://www.springframework.org/schema/data/mongo/spring-mongo-1.2.xsd=org/springframework/data/mongodb/config/spring-mongo-1.2.xsd http\://www.springframework.org/schema/data/mongo/spring-mongo-1.3.xsd=org/springframework/data/mongodb/config/spring-mongo-1.3.xsd http\://www.springframework.org/schema/data/mongo/spring-mongo-1.4.xsd=org/springframework/data/mongodb/config/spring-mongo-1.4.xsd -http\://www.springframework.org/schema/data/mongo/spring-mongo.xsd=org/springframework/data/mongodb/config/spring-mongo-1.4.xsd +http\://www.springframework.org/schema/data/mongo/spring-mongo-1.5.xsd=org/springframework/data/mongodb/config/spring-mongo-1.5.xsd +http\://www.springframework.org/schema/data/mongo/spring-mongo.xsd=org/springframework/data/mongodb/config/spring-mongo-1.5.xsd diff --git a/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.5.xsd b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.5.xsd new file mode 100644 index 000000000..9b225e6a4 --- /dev/null +++ b/spring-data-mongodb/src/main/resources/org/springframework/data/mongodb/config/spring-mongo-1.5.xsd @@ -0,0 +1,657 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The WriteConcern that will be the default value used when asking the MongoDbFactory for a DB object + + + + + + + + + + + + + + The reference to a MongoTemplate. Will default to 'mongoTemplate'. + + + + + + + Enables creation of indexes for queries that get derived from the method name + and thus reference domain class properties. Defaults to false. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The reference to a DbFactory. + + + + + + + + + + + + The reference to a MongoTypeMapper to be used by this MappingMongoConverter. + + + + + + + The reference to a MappingContext. Will default to 'mappingContext'. + + + + + + + Disables JSR-303 validation on MongoDB documents before they are saved. By default it is set to false. + + + + + + + + + + Enables abbreviating the field names for domain class properties to the + first character of their camel case names, e.g. fooBar -> fb. + + + + + + + + + + The reference to a MappingContext. Will default to 'mappingContext'. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The WriteConcern that will be the default value used when asking the MongoDbFactory for a DB object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A reference to a custom converter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The reference to a DbFactory. + + + + + + + + + + + + The WriteConcern that will be the default value used when asking the MongoDbFactory for a DB object + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The reference to a DbFactory. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/LowerCaseWithUnderscoresFieldNamingStrategyUnitTests.java b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/LowerCaseWithUnderscoresFieldNamingStrategyUnitTests.java new file mode 100644 index 000000000..19358bf58 --- /dev/null +++ b/spring-data-mongodb/src/test/java/org/springframework/data/mongodb/core/mapping/LowerCaseWithUnderscoresFieldNamingStrategyUnitTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2013 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.mongodb.core.mapping; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +/** + * Unit tests for {@link LowerCaseWithUnderscoresFieldNamingStrategy}. + * + * @author Ryan Tenney + */ +@RunWith(MockitoJUnitRunner.class) +public class LowerCaseWithUnderscoresFieldNamingStrategyUnitTests { + + FieldNamingStrategy strategy = new LowerCaseWithUnderscoresFieldNamingStrategy(); + + @Mock MongoPersistentProperty property; + + @Test + public void foo() { + + assertFieldNameForPropertyName("fooBar", "foo_bar"); + assertFieldNameForPropertyName("FooBar", "foo_bar"); + assertFieldNameForPropertyName("foo_bar", "foo_bar"); + assertFieldNameForPropertyName("FOO_BAR", "foo_bar"); + } + + private void assertFieldNameForPropertyName(String propertyName, String fieldName) { + + when(property.getName()).thenReturn(propertyName); + assertThat(strategy.getFieldName(property), is(fieldName)); + } +}