From 98b8129a743bb1374ec4bf7d5aca76a3456482d2 Mon Sep 17 00:00:00 2001 From: Nick Williams Date: Fri, 9 Aug 2013 22:28:27 -0500 Subject: [PATCH] DATACMNS-357 - Added support for primitive ids in EntityInformation. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AbstractEntityInformation now detects primitive id types and adapts the isNew state according to the Java Language Specification ยง4.12.5. Supported are primitive Numbers and the entity is considered new if the value of the primitive field is zero. Original pull request: #37. --- .../support/AbstractEntityInformation.java | 18 ++++- .../AbstractEntityInformationUnitTests.java | 79 ++++++++++++++++++- .../support/DummyEntityAndIdInformation.java | 57 +++++++++++++ 3 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/springframework/data/repository/core/support/DummyEntityAndIdInformation.java 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; + } +}