From 6a694f9d47f4cd96946a025903f6d2193ea14d5f Mon Sep 17 00:00:00 2001 From: Younes El Ouarti Date: Wed, 4 Dec 2024 12:04:26 +0100 Subject: [PATCH] impl of fix --- CHANGELOG.md | 2 + README.md | 9 ++++ .../model/hal/HalEmbeddedWrapper.java | 2 + .../model/hal/HalResourceWrapper.java | 6 +++ .../hateoflux/model/hal/HalWrapper.java | 8 ++++ .../model/hal/HalEmbeddedWrapperTest.java | 45 +++++++++++++++++++ .../hateoflux/model/hal/HalWrapperTest.java | 36 +++++++++++++++ .../ManualSerializationTest.java | 1 - 8 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/test/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapperTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index a7cf5d3..5e4e152 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### Changed +* HalResourecWrapperis#EmbeddedOriginallyAList is now private ### Fixed +* Single scalars (e.g. String, Integers, Boolean, etc.) are now not allowed in Wrappers and will result in an exception ## [1.0.0] diff --git a/README.md b/README.md index 05e7e75..6f69879 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,15 @@ ___ hateoflux is a lightweight, reactive-first Java library designed to streamline the creation of hypermedia-driven APIs in Spring WebFlux applications. It addresses the limitations of Spring HATEOAS in reactive environments, offering a more intuitive and maintainable approach to building HAL+JSON compliant APIs. +
+

+Getting Started | +Cookbook | +Documentation | +Demos +

+ + ## Table of Contents - [Why hateoflux?](#why-hateoflux) diff --git a/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapper.java b/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapper.java index f2e37f0..7f9d3b7 100644 --- a/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapper.java +++ b/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapper.java @@ -113,6 +113,8 @@ public static HalEmbeddedWrapper wrap(EmbeddedT resourceT } Assert.isTrue(!(resourceToWrap instanceof Iterable), valueIsNotAllowedToBeOfType("Resource to embed", "collection/iterable")); + Assert.isTrue(!isScalar(resourceToWrap.getClass()), valueIsNotAllowedToBeOfType("Embedded", + "scalar (e.g. String, int, etc.)")); return new HalEmbeddedWrapper<>(resourceToWrap); } diff --git a/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalResourceWrapper.java b/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalResourceWrapper.java index 917a97f..237f1e8 100644 --- a/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalResourceWrapper.java +++ b/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalResourceWrapper.java @@ -23,8 +23,10 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonUnwrapped; import de.kamillionlabs.hateoflux.model.link.Link; +import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.Setter; import org.springframework.lang.NonNull; import org.springframework.util.Assert; @@ -65,6 +67,8 @@ public final class HalResourceWrapper private Map.Entry>> embedded; @JsonIgnore + @Getter(AccessLevel.NONE) + @Setter(AccessLevel.NONE) private Boolean isEmbeddedOriginallyAList; @JsonProperty("_embedded") @@ -131,6 +135,8 @@ public static HalResourceWrapper wrap(@NonNull Reso Assert.isTrue(!(resource instanceof Iterable), valueIsNotAllowedToBeOfType("Resource", "collection" + "/iterable. " + "Use HalListWrapper instead")); + Assert.isTrue(!isScalar(resource.getClass()), valueIsNotAllowedToBeOfType("Resource", + "scalar (e.g. String, int, etc.)")); return new HalResourceWrapper<>(resource); } diff --git a/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalWrapper.java b/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalWrapper.java index 1ac1a23..f27b4f8 100644 --- a/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalWrapper.java +++ b/src/main/java/de/kamillionlabs/hateoflux/model/hal/HalWrapper.java @@ -281,5 +281,13 @@ protected static String determineRelationNameForObject(Object object) { } } + protected static boolean isScalar(Class clazz) { + return clazz.isPrimitive() + || clazz.equals(String.class) + || Number.class.isAssignableFrom(clazz) + || clazz.equals(Boolean.class) + || clazz.equals(Character.class); + } + } diff --git a/src/test/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapperTest.java b/src/test/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapperTest.java new file mode 100644 index 0000000..55b22a3 --- /dev/null +++ b/src/test/java/de/kamillionlabs/hateoflux/model/hal/HalEmbeddedWrapperTest.java @@ -0,0 +1,45 @@ +package de.kamillionlabs.hateoflux.model.hal; + +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; + +class HalEmbeddedWrapperTest { + + @Test + void givenString_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalEmbeddedWrapper.wrap("hello")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Embedded is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenCharacter_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalEmbeddedWrapper.wrap('h')) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Embedded is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenPrimitiveInt_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalEmbeddedWrapper.wrap(3)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Embedded is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenBigDecimal_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalEmbeddedWrapper.wrap(new BigDecimal("4536433.58"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Embedded is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenBoolean_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalEmbeddedWrapper.wrap(false)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Embedded is not allowed to be of type scalar (e.g. String, int, etc.)"); + } +} \ No newline at end of file diff --git a/src/test/java/de/kamillionlabs/hateoflux/model/hal/HalWrapperTest.java b/src/test/java/de/kamillionlabs/hateoflux/model/hal/HalWrapperTest.java index 03f92d4..f442864 100644 --- a/src/test/java/de/kamillionlabs/hateoflux/model/hal/HalWrapperTest.java +++ b/src/test/java/de/kamillionlabs/hateoflux/model/hal/HalWrapperTest.java @@ -7,6 +7,7 @@ import org.assertj.core.api.AssertionsForClassTypes; import org.junit.jupiter.api.Test; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -79,4 +80,39 @@ void givenEmptyCollection_whenDetermineRelationNameForObject_thenThrowsException .isInstanceOf(IllegalArgumentException.class) .hasMessage("Iterable cannot be empty when determining relation names"); } + + @Test + void givenString_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalResourceWrapper.wrap("hello")) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Resource is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenCharacter_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalResourceWrapper.wrap('h')) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Resource is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenPrimitiveInt_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalResourceWrapper.wrap(3)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Resource is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenBigDecimal_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalResourceWrapper.wrap(new BigDecimal("4536433.58"))) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Resource is not allowed to be of type scalar (e.g. String, int, etc.)"); + } + + @Test + void givenBoolean_whenWrapping_thenThrowsException() { + assertThatThrownBy(() -> HalResourceWrapper.wrap(false)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessage("Resource is not allowed to be of type scalar (e.g. String, int, etc.)"); + } } \ No newline at end of file diff --git a/src/test/java/de/kamillionlabs/hateoflux/model/hal/serialization/ManualSerializationTest.java b/src/test/java/de/kamillionlabs/hateoflux/model/hal/serialization/ManualSerializationTest.java index a25dad4..4fdc2ce 100644 --- a/src/test/java/de/kamillionlabs/hateoflux/model/hal/serialization/ManualSerializationTest.java +++ b/src/test/java/de/kamillionlabs/hateoflux/model/hal/serialization/ManualSerializationTest.java @@ -309,7 +309,6 @@ public void givenHalListWrapperWithEmbeddingListsAndEmptyOnes_whenSerialized_the String actualJson = mapper.writeValueAsString(halListWrapper); // THEN - System.out.println(actualJson); JSONAssert.assertEquals(""" { "_embedded": {