diff --git a/src/main/java/org/springframework/data/mapping/model/CamelCaseAbbreviatingFieldNamingStrategy.java b/src/main/java/org/springframework/data/mapping/model/CamelCaseAbbreviatingFieldNamingStrategy.java new file mode 100644 index 000000000..e0068fec7 --- /dev/null +++ b/src/main/java/org/springframework/data/mapping/model/CamelCaseAbbreviatingFieldNamingStrategy.java @@ -0,0 +1,42 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.model; + +/** + * {@link FieldNamingStrategy} that abbreviates field names by using the very first letter of the camel case parts of + * the {@link MongoPersistentProperty}'s name. + * + * @since 1.9 + * @author Oliver Gierke + */ +public class CamelCaseAbbreviatingFieldNamingStrategy extends CamelCaseSplittingFieldNamingStrategy { + + /** + * Creates a new {@link CamelCaseAbbreviatingFieldNamingStrategy}. + */ + public CamelCaseAbbreviatingFieldNamingStrategy() { + super(""); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mongodb.core.mapping.CamelCaseSplittingFieldNamingStrategy#preparePart(java.lang.String) + */ + @Override + protected String preparePart(String part) { + return part.substring(0, 1); + } +} diff --git a/src/main/java/org/springframework/data/mapping/model/CamelCaseSplittingFieldNamingStrategy.java b/src/main/java/org/springframework/data/mapping/model/CamelCaseSplittingFieldNamingStrategy.java new file mode 100644 index 000000000..fef66ed84 --- /dev/null +++ b/src/main/java/org/springframework/data/mapping/model/CamelCaseSplittingFieldNamingStrategy.java @@ -0,0 +1,80 @@ +/* + * Copyright 2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.model; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.util.ParsingUtils; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * Configurable {@link FieldNamingStrategy} that splits up camel-case property names and reconcatenates them using a + * configured delimiter. Individual parts of the name can be manipulated using {@link #preparePart(String)}. + * + * @author Oliver Gierke + * @since 1.9 + */ +public class CamelCaseSplittingFieldNamingStrategy implements FieldNamingStrategy { + + private final String delimiter; + + /** + * Creates a new {@link CamelCaseSplittingFieldNamingStrategy}. + * + * @param delimiter must not be {@literal null}. + */ + public CamelCaseSplittingFieldNamingStrategy(String delimiter) { + + Assert.notNull(delimiter, "Delimiter must not be null!"); + this.delimiter = delimiter; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.model.FieldNamingStrategy#getFieldName(org.springframework.data.mapping.PersistentProperty) + */ + @Override + public String getFieldName(PersistentProperty property) { + + List parts = ParsingUtils.splitCamelCaseToLower(property.getName()); + List result = new ArrayList(); + + for (String part : parts) { + + String candidate = preparePart(part); + + if (StringUtils.hasText(candidate)) { + result.add(candidate); + } + } + + return StringUtils.collectionToDelimitedString(result, delimiter); + } + + /** + * Callback to prepare the uncapitalized part obtained from the split up of the camel case source. Default + * implementation returns the part as is. + * + * @param part + * @return + */ + protected String preparePart(String part) { + return part; + } +} diff --git a/src/main/java/org/springframework/data/mapping/model/FieldNamingStrategy.java b/src/main/java/org/springframework/data/mapping/model/FieldNamingStrategy.java new file mode 100644 index 000000000..043833dfd --- /dev/null +++ b/src/main/java/org/springframework/data/mapping/model/FieldNamingStrategy.java @@ -0,0 +1,38 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.model; + +import org.springframework.data.mapping.PersistentProperty; + +/** + * SPI to determine how to name document fields in cases the field name is not manually defined. + * + * @see PropertyNameFieldNamingStrategy + * @see CamelCaseAbbreviatingFieldNamingStrategy + * @see SnakeCaseFieldNamingStrategy + * @since 1.9 + * @author Oliver Gierke + */ +public interface FieldNamingStrategy { + + /** + * Returns the field name to be used for the given {@link MongoPersistentProperty}. + * + * @param property must not be {@literal null} or empty; + * @return + */ + String getFieldName(PersistentProperty property); +} diff --git a/src/main/java/org/springframework/data/mapping/model/PropertyNameFieldNamingStrategy.java b/src/main/java/org/springframework/data/mapping/model/PropertyNameFieldNamingStrategy.java new file mode 100644 index 000000000..88e54c7c6 --- /dev/null +++ b/src/main/java/org/springframework/data/mapping/model/PropertyNameFieldNamingStrategy.java @@ -0,0 +1,37 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.model; + +import org.springframework.data.mapping.PersistentProperty; + +/** + * {@link FieldNamingStrategy} simply using the {@link MongoPersistentProperty}'s name. + * + * @since 1.9 + * @author Oliver Gierke + */ +public enum PropertyNameFieldNamingStrategy implements FieldNamingStrategy { + + INSTANCE; + + /* + * (non-Javadoc) + * @see org.springframework.data.mapping.model.FieldNamingStrategy#getFieldName(org.springframework.data.mapping.PersistentProperty) + */ + public String getFieldName(PersistentProperty property) { + return property.getName(); + } +} diff --git a/src/main/java/org/springframework/data/mapping/model/SnakeCaseFieldNamingStrategy.java b/src/main/java/org/springframework/data/mapping/model/SnakeCaseFieldNamingStrategy.java new file mode 100644 index 000000000..30b53a845 --- /dev/null +++ b/src/main/java/org/springframework/data/mapping/model/SnakeCaseFieldNamingStrategy.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.model; + +/** + * {@link FieldNamingStrategy} that translates typical camel case Java property names to lower case JSON element names, + * separated by underscores. + * + * @since 1.5 + * @author Ryan Tenney + * @author Oliver Gierke + */ +public class SnakeCaseFieldNamingStrategy extends CamelCaseSplittingFieldNamingStrategy { + + /** + * Creates a new {@link SnakeCaseFieldNamingStrategy}. + */ + public SnakeCaseFieldNamingStrategy() { + super("_"); + } +} diff --git a/src/test/java/org/springframework/data/mapping/model/CamelCaseAbbreviatingFieldNamingStrategyUnitTests.java b/src/test/java/org/springframework/data/mapping/model/CamelCaseAbbreviatingFieldNamingStrategyUnitTests.java new file mode 100644 index 000000000..e998e5c35 --- /dev/null +++ b/src/test/java/org/springframework/data/mapping/model/CamelCaseAbbreviatingFieldNamingStrategyUnitTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.model; + +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; +import org.springframework.data.mapping.PersistentProperty; + +/** + * Unit tests for {@link CamelCaseAbbreviatingFieldNamingStrategy}. + * + * @author Oliver Gierke + * @since 1.9 + */ +@RunWith(MockitoJUnitRunner.class) +public class CamelCaseAbbreviatingFieldNamingStrategyUnitTests { + + FieldNamingStrategy strategy = new CamelCaseAbbreviatingFieldNamingStrategy(); + + @Mock PersistentProperty property; + + /** + * @see DATACMNS-523 + */ + @Test + public void abbreviatesToCamelCase() { + + assertFieldNameForPropertyName("fooBar", "fb"); + assertFieldNameForPropertyName("fooBARFooBar", "fbfb"); + } + + private void assertFieldNameForPropertyName(String propertyName, String fieldName) { + + when(property.getName()).thenReturn(propertyName); + assertThat(strategy.getFieldName(property), is(fieldName)); + } +} diff --git a/src/test/java/org/springframework/data/mapping/model/SnakeCaseFieldNamingStrategyUnitTests.java b/src/test/java/org/springframework/data/mapping/model/SnakeCaseFieldNamingStrategyUnitTests.java new file mode 100644 index 000000000..94701358d --- /dev/null +++ b/src/test/java/org/springframework/data/mapping/model/SnakeCaseFieldNamingStrategyUnitTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2013-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.mapping.model; + +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; +import org.springframework.data.mapping.PersistentProperty; + +/** + * Unit tests for {@link SnakeCaseFieldNamingStrategy}. + * + * @author Ryan Tenney + * @author Oliver Gierke + * @since 1.9 + */ +@RunWith(MockitoJUnitRunner.class) +public class SnakeCaseFieldNamingStrategyUnitTests { + + FieldNamingStrategy strategy = new SnakeCaseFieldNamingStrategy(); + + @Mock PersistentProperty property; + + /** + * @see DATACMNS-523 + */ + @Test + public void rendersSnakeCaseFieldNames() { + + 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)); + } +}