diff --git a/src/main/java/org/springframework/data/repository/core/support/AbstractEntityInformation.java b/src/main/java/org/springframework/data/repository/core/support/AbstractEntityInformation.java index d297c1b66..3849e5395 100644 --- a/src/main/java/org/springframework/data/repository/core/support/AbstractEntityInformation.java +++ b/src/main/java/org/springframework/data/repository/core/support/AbstractEntityInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2011 the original author or authors. + * Copyright 2011-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. @@ -25,11 +25,15 @@ import org.springframework.util.Assert; * {@link #getId(Object)} returns {@literal null}. * * @author Oliver Gierke + * @author Nick Williams */ public abstract class AbstractEntityInformation implements EntityInformation { private final Class domainClass; + private boolean idTypePrimitiveSet; + private boolean idTypePrimitive; + /** * Creates a new {@link AbstractEntityInformation} from the given domain class. * @@ -50,7 +54,8 @@ public abstract class AbstractEntityInformation impl */ public boolean isNew(T entity) { - return getId(entity) == null; + ID id = getId(entity); + return id == null || this.isIdTypePrimitive() && id instanceof Number && ((Number) id).longValue() == 0; } /* @@ -64,4 +69,13 @@ public abstract class AbstractEntityInformation impl return this.domainClass; } + + protected boolean isIdTypePrimitive() { + if (!this.idTypePrimitiveSet) { + this.idTypePrimitive = getIdType() != null && getIdType().isPrimitive(); + this.idTypePrimitiveSet = true; + } + + return this.idTypePrimitive; + } } diff --git a/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java b/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java index 71008561d..54ec1c62a 100644 --- a/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java +++ b/src/test/java/org/springframework/data/repository/core/support/AbstractEntityInformationUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2011-2012 the original author or authors. + * Copyright 2011-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. @@ -21,12 +21,14 @@ import static org.junit.Assert.*; import java.io.Serializable; import org.junit.Test; +import org.springframework.data.domain.Persistable; import org.springframework.data.repository.core.EntityInformation; /** * Unit tests for {@link AbstractEntityInformation}. * * @author Oliver Gierke + * @author Nick Williams */ public class AbstractEntityInformationUnitTests { @@ -43,4 +45,79 @@ public class AbstractEntityInformationUnitTests { assertThat(metadata.isNew(null), is(true)); assertThat(metadata.isNew(new Object()), is(false)); } + + // See DATACMNS-357 + @Test + public void considersEntityNewIfGetIdReturnsNullAndIdTypeIsPrimitiveNumber() throws Exception { + + EntityInformation metadata1 = + new DummyEntityAndIdInformation(LongIdEntity.class, long.class); + assertThat(metadata1.isNew(null), is(true)); + assertThat(metadata1.isNew(new LongIdEntity(null)), is(true)); + assertThat(metadata1.isNew(new LongIdEntity(-1L)), is(true)); + assertThat(metadata1.isNew(new LongIdEntity(0L)), is(true)); + assertThat(metadata1.isNew(new LongIdEntity(1L)), is(false)); + + EntityInformation metadata2 = + new DummyEntityAndIdInformation(IntIdEntity.class, int.class); + assertThat(metadata2.isNew(null), is(true)); + assertThat(metadata2.isNew(new IntIdEntity(null)), is(true)); + assertThat(metadata2.isNew(new IntIdEntity(-1)), is(true)); + assertThat(metadata2.isNew(new IntIdEntity(0)), is(true)); + assertThat(metadata2.isNew(new IntIdEntity(1)), is(false)); + } + + // See DATACMNS-357 + @Test + public void considersEntityNewIfGetIdReturnsNullAndIdTypeIsPrimitiveWrapperNumber() throws Exception { + + EntityInformation metadata1 = + new DummyEntityAndIdInformation(LongIdEntity.class, Long.class); + assertThat(metadata1.isNew(null), is(true)); + assertThat(metadata1.isNew(new LongIdEntity(null)), is(true)); + assertThat(metadata1.isNew(new LongIdEntity(-1L)), is(false)); + assertThat(metadata1.isNew(new LongIdEntity(0L)), is(false)); + assertThat(metadata1.isNew(new LongIdEntity(1L)), is(false)); + + EntityInformation metadata2 = + new DummyEntityAndIdInformation(IntIdEntity.class, Integer.class); + assertThat(metadata2.isNew(null), is(true)); + assertThat(metadata2.isNew(new IntIdEntity(null)), is(true)); + assertThat(metadata2.isNew(new IntIdEntity(-1)), is(false)); + assertThat(metadata2.isNew(new IntIdEntity(0)), is(false)); + assertThat(metadata2.isNew(new IntIdEntity(1)), is(false)); + } + + private static abstract class NumberIdEntity implements Persistable { + + private final T id; + + public NumberIdEntity(T id) { + this.id = id; + } + + @Override + public T getId() { + return this.id; + } + + @Override + public boolean isNew() { + throw new UnsupportedOperationException(); + } + } + + private static final class LongIdEntity extends NumberIdEntity { + + public LongIdEntity(Long id) { + super(id); + } + } + + private static final class IntIdEntity extends NumberIdEntity { + + public IntIdEntity(Integer id) { + super(id); + } + } } diff --git a/src/test/java/org/springframework/data/repository/core/support/DummyEntityAndIdInformation.java b/src/test/java/org/springframework/data/repository/core/support/DummyEntityAndIdInformation.java new file mode 100644 index 000000000..1400134ef --- /dev/null +++ b/src/test/java/org/springframework/data/repository/core/support/DummyEntityAndIdInformation.java @@ -0,0 +1,57 @@ +/* + * Copyright 2011-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.repository.core.support; + +import org.springframework.data.domain.Persistable; + +import java.io.Serializable; + +/** + * Dummy implementation of {@link AbstractEntityInformation} that also provides ID information. + * + * @author Nick Williams + */ +public class DummyEntityAndIdInformation, ID extends Serializable> + extends AbstractEntityInformation { + + private final Class idClass; + + /** + * Creates a new {@link DummyEntityInformation} for the given domain class. + * + * @param domainClass + */ + public DummyEntityAndIdInformation(Class domainClass, Class idClass) { + super(domainClass); + this.idClass = idClass; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.EntityInformation#getId(java.lang.Object) + */ + public ID getId(T entity) { + return entity == null ? null : entity.getId(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.EntityInformation#getIdType() + */ + public Class getIdType() { + return this.idClass; + } +}