diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentPropertyComparator.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentPropertyComparator.java index 9b52d6b90..cec01811b 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentPropertyComparator.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/CassandraPersistentPropertyComparator.java @@ -22,10 +22,10 @@ public enum CassandraPersistentPropertyComparator implements Comparator 0) { exceptions.add(new MappingException( - "Annotations @Id and @PrimaryKey are invalid for type annoated as @PrimaryKeyClass")); + "Annotations @Id and @PrimaryKey are invalid for type annotated with @PrimaryKeyClass")); } /* @@ -136,14 +137,7 @@ public class DefaultCassandraPersistentEntityMetadataVerifier implements Cassand /* * Ensure PrimaryKeyClass is Serializable */ - Class[] interfaces = thisType.getInterfaces(); - boolean isTypeSerializable = false; - for (Class c : interfaces) { - if (c.equals(Serializable.class)) { - isTypeSerializable = true; - } - } - if (!isTypeSerializable) { + if (!Serializable.class.isAssignableFrom(thisType)) { exceptions.add(new MappingException("@PrimaryKeyClass must be Serializable")); } @@ -163,7 +157,8 @@ public class DefaultCassandraPersistentEntityMetadataVerifier implements Cassand throw new NoSuchMethodException(); } } catch (NoSuchMethodException e) { - exceptions.add(new MappingException("@PrimaryKeyClass must override 'boolean equals(Object)' method")); + exceptions.add(new MappingException( + "@PrimaryKeyClass must override 'boolean equals(Object)' method and use all @PrimaryKeyColumn fields", e)); } /* @@ -175,8 +170,10 @@ public class DefaultCassandraPersistentEntityMetadataVerifier implements Cassand throw new NoSuchMethodException(); } } catch (NoSuchMethodException e) { - exceptions.add(new MappingException("@PrimaryKeyClass must override 'int hashCode()' method")); + exceptions.add(new MappingException( + "@PrimaryKeyClass must override 'int hashCode()' method and use all @PrimaryKeyColumn fields", e)); } + } /* @@ -185,35 +182,29 @@ public class DefaultCassandraPersistentEntityMetadataVerifier implements Cassand if (isTable) { /* - * Ensure at least 1 PK + * Ensure only one PK */ - if (idProperties.size() == 0 && compositePrimaryKeys.size() == 0) { - exceptions.add(new MappingException("@Table/@Persistent types must have at least 1 @PrimaryKey attribute")); - } - - /* - * Ensure no more than 1 PK - */ - if (idProperties.size() + compositePrimaryKeys.size() > 1) { - exceptions.add(new MappingException("@Table/@Persistent must have only 1 @PrimaryKey attribute")); + int idPropertyCount = idProperties.size(); + if (idPropertyCount != 1) { + exceptions.add(new MappingException(String.format( + "@Table/@Persistent types must have only one @PrimaryKey attribute. Found %s.", idPropertyCount))); } /* * Ensure that Id is a supported Type. At the point there is only 1. */ - if (idProperties.size() == 1) { - Class typeClass = idProperties.get(0).getType(); - if (!typeClass.isAnnotationPresent(PrimaryKeyClass.class) - && CassandraSimpleTypeHolder.getDataTypeFor(typeClass) == null) { - exceptions.add(new MappingException("Fields annotated with @PrimaryKey must be simple CassandraTypes")); - } + Class typeClass = idProperties.get(0).getType(); + if (!typeClass.isAnnotationPresent(PrimaryKeyClass.class) + && CassandraSimpleTypeHolder.getDataTypeFor(typeClass) == null) { + exceptions.add(new MappingException( + "Fields annotated with @PrimaryKey must be simple CassandraTypes or @PrimaryKeyClass type")); } } /* * Determine whether or not to throw Exception based on errors found */ - if (exceptions.getErrorCount() > 0) { + if (exceptions.getCount() > 0) { throw exceptions; } } diff --git a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/VerifierMappingExceptions.java b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/VerifierMappingExceptions.java index 51d5190a4..ed43680a5 100644 --- a/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/VerifierMappingExceptions.java +++ b/spring-data-cassandra/src/main/java/org/springframework/data/cassandra/mapping/VerifierMappingExceptions.java @@ -29,8 +29,7 @@ import org.springframework.data.mapping.model.MappingException; */ public class VerifierMappingExceptions extends MappingException { - Collection messages = new LinkedList(); - Collection errors = new LinkedList(); + Collection exceptions = new LinkedList(); /** * @param s @@ -43,16 +42,7 @@ public class VerifierMappingExceptions extends MappingException { * @param s */ public void add(MappingException e) { - messages.add(e.getMessage()); - errors.add(e); - } - - /** - * @param s - */ - public void add(String s, MappingException e) { - messages.add(s); - errors.add(e); + exceptions.add(e); } /** @@ -61,7 +51,7 @@ public class VerifierMappingExceptions extends MappingException { * @return The Collection of MappingException */ public Collection getMappingExceptions() { - return errors; + return exceptions; } /** @@ -69,7 +59,11 @@ public class VerifierMappingExceptions extends MappingException { * * @return The Collection of Messages */ - public Collection getMappingExceptionMessages() { + public Collection getMessages() { + Collection messages = new LinkedList(); + for (MappingException e : exceptions) { + messages.add(e.getMessage()); + } return messages; } @@ -78,15 +72,15 @@ public class VerifierMappingExceptions extends MappingException { * * @return Number of Errors present */ - public int getErrorCount() { - return errors.size(); + public int getCount() { + return exceptions.size(); } @Override public String getMessage() { StringBuilder builder = new StringBuilder(); - for (String s : messages) { - builder.append(s).append("\n"); + for (MappingException e : exceptions) { + builder.append(e.getMessage()).append("\n"); } return builder.toString(); } diff --git a/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/unit/BasicCassandraPersistentEntityOrderPropertiesTest.java b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/unit/BasicCassandraPersistentEntityOrderPropertiesTest.java new file mode 100644 index 000000000..62a792d85 --- /dev/null +++ b/spring-data-cassandra/src/test/java/org/springframework/data/cassandra/test/unit/BasicCassandraPersistentEntityOrderPropertiesTest.java @@ -0,0 +1,172 @@ +/* + * 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. + * 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.cassandra.test.unit; + +import static org.junit.Assert.assertEquals; + +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.cassandra.core.PrimaryKeyType; +import org.springframework.data.annotation.Id; +import org.springframework.data.cassandra.mapping.CassandraPersistentEntity; +import org.springframework.data.cassandra.mapping.CassandraPersistentProperty; +import org.springframework.data.cassandra.mapping.DefaultCassandraMappingContext; +import org.springframework.data.cassandra.mapping.PrimaryKey; +import org.springframework.data.cassandra.mapping.PrimaryKeyClass; +import org.springframework.data.cassandra.mapping.PrimaryKeyColumn; +import org.springframework.data.cassandra.mapping.Table; +import org.springframework.data.mapping.PropertyHandler; + +/** + * @author David Webb + * + */ +public class BasicCassandraPersistentEntityOrderPropertiesTest { + + private List expected; + private DefaultCassandraMappingContext mappingContext = new DefaultCassandraMappingContext(); + + @Before + public void init() { + } + + @Test + public void testCompositeKeyPropertyOrder() { + + CassandraPersistentEntity entity = mappingContext.getPersistentEntity(CompositePK.class); + + expected = new LinkedList(); + expected.add(entity.getPersistentProperty("key0")); + expected.add(entity.getPersistentProperty("key1")); + expected.add(entity.getPersistentProperty("key2")); + + final List actual = new LinkedList(); + + entity.doWithProperties(new PropertyHandler() { + + @Override + public void doWithPersistentProperty(CassandraPersistentProperty persistentProperty) { + actual.add(persistentProperty); + } + }); + + assertEquals(expected, actual); + + } + + @Test + public void testTablePropertyOrder() { + + CassandraPersistentEntity entity = mappingContext.getPersistentEntity(CompositeKeyEntity.class); + + expected = new LinkedList(); + expected.add(entity.getPersistentProperty("key")); + expected.add(entity.getPersistentProperty("attribute")); + expected.add(entity.getPersistentProperty("text")); + + final List actual = new LinkedList(); + + entity.doWithProperties(new PropertyHandler() { + + @Override + public void doWithPersistentProperty(CassandraPersistentProperty persistentProperty) { + actual.add(persistentProperty); + } + }); + + assertEquals(expected, actual); + + } + + @Table + static class CompositeKeyEntity { + + @PrimaryKey + private CompositePK key; + + private String attribute; + + private String text; + + } + + /** + * This is intentionally using dumb ordinals + */ + @PrimaryKeyClass + static class CompositePK implements Serializable { + + @PrimaryKeyColumn(ordinal = 2, type = PrimaryKeyType.PARTITIONED) + private String key0; + + @PrimaryKeyColumn(ordinal = 0) + private String key1; + + @PrimaryKeyColumn(ordinal = 1) + private String key2; + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((key0 == null) ? 0 : key0.hashCode()); + result = prime * result + ((key1 == null) ? 0 : key1.hashCode()); + result = prime * result + ((key2 == null) ? 0 : key2.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + CompositePK other = (CompositePK) obj; + if (key0 == null) { + if (other.key0 != null) + return false; + } else if (!key0.equals(other.key0)) + return false; + if (key1 == null) { + if (other.key1 != null) + return false; + } else if (!key1.equals(other.key1)) + return false; + if (key2 == null) { + if (other.key2 != null) + return false; + } else if (!key2.equals(other.key2)) + return false; + return true; + } + + } + + @Table + static class SimpleKeyEntity { + + @Id + private String id; + + } + +}