diff --git a/src/main/java/org/springframework/data/domain/DoubleVector.java b/src/main/java/org/springframework/data/domain/DoubleVector.java index 623d6a011..b3669c4f7 100644 --- a/src/main/java/org/springframework/data/domain/DoubleVector.java +++ b/src/main/java/org/springframework/data/domain/DoubleVector.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 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. @@ -30,7 +30,7 @@ class DoubleVector implements Vector { private final double[] v; - public DoubleVector(double[] v) { + DoubleVector(double[] v) { this.v = v; } @@ -39,10 +39,11 @@ class DoubleVector implements Vector { */ static Vector copy(double[] v) { - double[] copy = new double[v.length]; - System.arraycopy(v, 0, copy, 0, copy.length); + if (v.length == 0) { + return new DoubleVector(new double[0]); + } - return new DoubleVector(copy); + return new DoubleVector(Arrays.copyOf(v, v.length)); } /** @@ -50,6 +51,10 @@ class DoubleVector implements Vector { */ static Vector copy(Collection v) { + if (v.isEmpty()) { + return new DoubleVector(new double[0]); + } + double[] copy = new double[v.size()]; int i = 0; for (Number number : v) { @@ -87,11 +92,7 @@ class DoubleVector implements Vector { @Override public double[] toDoubleArray() { - - double[] copy = new double[this.v.length]; - System.arraycopy(this.v, 0, copy, 0, copy.length); - - return copy; + return Arrays.copyOf(this.v, this.v.length); } @Override diff --git a/src/main/java/org/springframework/data/domain/FloatVector.java b/src/main/java/org/springframework/data/domain/FloatVector.java index bb07df19c..d2d85f438 100644 --- a/src/main/java/org/springframework/data/domain/FloatVector.java +++ b/src/main/java/org/springframework/data/domain/FloatVector.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 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. @@ -30,7 +30,7 @@ class FloatVector implements Vector { private final float[] v; - public FloatVector(float[] v) { + FloatVector(float[] v) { this.v = v; } @@ -39,10 +39,11 @@ class FloatVector implements Vector { */ static Vector copy(float[] v) { - float[] copy = new float[v.length]; - System.arraycopy(v, 0, copy, 0, copy.length); + if (v.length == 0) { + return new FloatVector(new float[0]); + } - return new FloatVector(copy); + return new FloatVector(Arrays.copyOf(v, v.length)); } /** @@ -50,6 +51,10 @@ class FloatVector implements Vector { */ static Vector copy(Collection v) { + if (v.isEmpty()) { + return new FloatVector(new float[0]); + } + float[] copy = new float[v.size()]; int i = 0; for (Number number : v) { @@ -76,11 +81,7 @@ class FloatVector implements Vector { @Override public float[] toFloatArray() { - - float[] copy = new float[this.v.length]; - System.arraycopy(this.v, 0, copy, 0, copy.length); - - return copy; + return Arrays.copyOf(this.v, this.v.length); } @Override diff --git a/src/main/java/org/springframework/data/domain/NumberVector.java b/src/main/java/org/springframework/data/domain/NumberVector.java index b71dd7081..528916e86 100644 --- a/src/main/java/org/springframework/data/domain/NumberVector.java +++ b/src/main/java/org/springframework/data/domain/NumberVector.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 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. @@ -18,6 +18,7 @@ package org.springframework.data.domain; import java.util.Arrays; import java.util.Collection; +import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** @@ -30,7 +31,9 @@ class NumberVector implements Vector { private final Number[] v; - public NumberVector(Number[] v) { + NumberVector(Number[] v) { + + Assert.noNullElements(v, "Vector [v] must not contain null elements"); this.v = v; } @@ -39,41 +42,39 @@ class NumberVector implements Vector { */ static Vector copy(Number[] v) { - Number[] copy = new Number[v.length]; - System.arraycopy(v, 0, copy, 0, copy.length); + if (v.length == 0) { + return new NumberVector(new Number[0]); + } - return new NumberVector(copy); + return new NumberVector(Arrays.copyOf(v, v.length)); } /** * Copy the given {@link Number} and wrap it within a Vector. */ - static Vector copy(Collection numbers) { + static Vector copy(Collection v) { - Number[] copy = new Number[numbers.size()]; - - int i = 0; - for (Number number : numbers) { - copy[i++] = number; + if (v.isEmpty()) { + return new NumberVector(new Number[0]); } - return new NumberVector(copy); + return new NumberVector(v.toArray(Number[]::new)); } @Override public Class getType() { - Class candidate = null; - for (Object val : v) { - if (val != null) { - if (candidate == null) { - candidate = val.getClass(); - } else if (candidate != val.getClass()) { - return Number.class; - } + if (this.v.length == 0) { + return Number.class; + } + + Class candidate = this.v[0].getClass(); + for (int i = 1; i < this.v.length; i++) { + if (candidate != this.v[i].getClass()) { + return Number.class; } } - return (Class) candidate; + return candidate; } @Override diff --git a/src/main/java/org/springframework/data/domain/Vector.java b/src/main/java/org/springframework/data/domain/Vector.java index d1e0cfa25..db434e0f7 100644 --- a/src/main/java/org/springframework/data/domain/Vector.java +++ b/src/main/java/org/springframework/data/domain/Vector.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 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. @@ -75,6 +75,9 @@ public interface Vector { static Vector of(Collection values) { Assert.notNull(values, "Vector values must not be null"); + if(values.isEmpty()) { + return NumberVector.copy(new Number[0]); + } Class cet = CollectionUtils.findCommonElementType(values); diff --git a/src/test/java/org/springframework/data/domain/FloatVectorUnitTests.java b/src/test/java/org/springframework/data/domain/FloatVectorUnitTests.java index bef96f4e8..c58d5d047 100644 --- a/src/test/java/org/springframework/data/domain/FloatVectorUnitTests.java +++ b/src/test/java/org/springframework/data/domain/FloatVectorUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 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. diff --git a/src/test/java/org/springframework/data/domain/NumberVectorUnitTests.java b/src/test/java/org/springframework/data/domain/NumberVectorUnitTests.java index 644113f41..ba730de0f 100644 --- a/src/test/java/org/springframework/data/domain/NumberVectorUnitTests.java +++ b/src/test/java/org/springframework/data/domain/NumberVectorUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 the original author or authors. + * Copyright 2025 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. @@ -15,9 +15,12 @@ */ package org.springframework.data.domain; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.Test; @@ -25,12 +28,40 @@ import org.junit.jupiter.api.Test; * Unit tests for {@link NumberVector}. * * @author Mark Paluch + * @author Christoph Strobl */ class NumberVectorUnitTests { Number[] values = new Number[] { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6f }; Number[] floats = new Number[] { (float) 1.1d, (float) 2.2d, (float) 3.3d, (float) 4.4d, (float) 5.5, 6.6 }; + @Test // GH-3193 + void shouldErrorOnNullElements() { + + List source = new ArrayList<>(3); + source.add(1L); + source.add(null); + source.add(3L); + + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> NumberVector.copy(source)); + assertThatExceptionOfType(IllegalArgumentException.class) + .isThrownBy(() -> NumberVector.copy(new Number[] { 1L, null, 3L })); + } + + @Test // GH-3193 + void shouldAcceptEmptySource() { + + Vector vector = NumberVector.copy(List.of()); + + assertThat(vector.size()).isEqualTo(0); + assertThat(vector.getType()).isEqualTo(Number.class); + + vector = NumberVector.copy(new Number[] {}); + + assertThat(vector.size()).isEqualTo(0); + assertThat(vector.getType()).isEqualTo(Number.class); + } + @Test // GH-3193 void shouldCreateVector() { @@ -48,6 +79,17 @@ class NumberVectorUnitTests { assertThat(vector.getSource()).isNotSameAs(vector).isEqualTo(values); } + @Test // GH-3193 + void shouldFigureOutCommonType() { + + assertThat(NumberVector.copy(List.of()).getType()).isEqualTo(Number.class); + assertThat(NumberVector.copy(List.of(1)).getType()).isEqualTo(Integer.class); + assertThat(NumberVector.copy(List.of(1L, 2L)).getType()).isEqualTo(Long.class); + assertThat(NumberVector.copy(List.of(1F, 2F)).getType()).isEqualTo(Float.class); + assertThat(NumberVector.copy(List.of(1D, 2D)).getType()).isEqualTo(Double.class); + assertThat(NumberVector.copy(List.of(1D, 2F, 3F)).getType()).isEqualTo(Number.class); + } + @Test // GH-3193 void shouldRenderToString() { @@ -66,7 +108,7 @@ class NumberVectorUnitTests { } @Test // GH-3193 - void sourceShouldReturnSource() { + void sourceShouldReturnSource() { // this one is questionable Vector vector = new NumberVector(values); diff --git a/src/test/java/org/springframework/data/domain/VectorUnitTests.java b/src/test/java/org/springframework/data/domain/VectorUnitTests.java new file mode 100644 index 000000000..4f5f3b024 --- /dev/null +++ b/src/test/java/org/springframework/data/domain/VectorUnitTests.java @@ -0,0 +1,36 @@ +/* + * Copyright 2025 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 + * + * https://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.domain; + +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +import java.util.Collection; + +import org.junit.jupiter.api.Test; + +/** + * @author Christoph Strobl + */ +public class VectorUnitTests { + + @Test // GH-3193 + void staticInitializersErrorOnNull() { + + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Vector.of((double[]) null)); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Vector.of((float[]) null)); + assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> Vector.of((Collection) null)); + } +}