From ded35c29336f7518498b268c7fbfddd4de20da63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Mikul=C3=A1=C5=A1ek?= Date: Fri, 12 Jul 2024 09:22:34 +0200 Subject: [PATCH] feat: allow to opt out links uri encoding --- lib/src/main/asciidoc/configuration.adoc | 1 + .../hateoas/jsonapi/JsonApiConfiguration.java | 15 ++++++++++++++- .../hateoas/jsonapi/JsonApiLinksSerializer.java | 10 ++++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/src/main/asciidoc/configuration.adoc b/lib/src/main/asciidoc/configuration.adoc index 7b2edbfe..90aa0d80 100644 --- a/lib/src/main/asciidoc/configuration.adoc +++ b/lib/src/main/asciidoc/configuration.adoc @@ -33,6 +33,7 @@ see https://jsonapi.org/format/#auto-id--link-objects. To serialize the Spring H Be aware that using the default, Spring HATEOAS complex links are rendered in a backward-incompatible way (related to version 1.x.x of this library that only supports JSON:API 1.0), since client might expect properties like title in the meta section. | true +| LinksUriEncoded | Whether the links should be URI encoded when serializing. Allowed by default. | true |=== TIP: Since the JSON:API recommendation contains square brackets in the request parameter names, diff --git a/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiConfiguration.java b/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiConfiguration.java index e95ffde6..a314e6ac 100644 --- a/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiConfiguration.java +++ b/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiConfiguration.java @@ -262,6 +262,19 @@ public enum AffordanceType { @Getter private final boolean jsonApiCompliantLinks; + /** + * By default, JSON:API links are serialized as URI encoded. + * + * If you set this configuration ro {@literal false}, Spring HATEOAS links won't be URI encoded. + * This can be useful for instance to avoid double uri encoding when you pass the links to the model already + * URI encoded. + * @param linksUriEncoded The new value of this configuration's linksUriEncoded + * @return The default is {@literal true}. + */ + @With + @Getter + private final boolean linksUriEncoded; + @With(AccessLevel.PRIVATE) private final Map, String> typeForClass; @@ -361,8 +374,8 @@ public JsonApiConfiguration() { this.affordancesRenderedAsLinkMeta = AffordanceType.NONE; this.jsonApi11LinkPropertiesRemovedFromLinkMeta = true; this.jsonApiCompliantLinks = true; + this.linksUriEncoded = true; this.objectMapperCustomizer = customObjectMapper -> { }; // Default to no action. } } - diff --git a/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiLinksSerializer.java b/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiLinksSerializer.java index 6a5680a1..abeb926c 100644 --- a/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiLinksSerializer.java +++ b/lib/src/main/java/com/toedter/spring/hateoas/jsonapi/JsonApiLinksSerializer.java @@ -47,6 +47,7 @@ class JsonApiLinksSerializer extends AbstractJsonApiSerializer { private static final ObjectMapper objectMapper = new ObjectMapper(); private JsonApiConfiguration.AffordanceType affordanceType; private boolean removeHateoasLinkPropertiesFromMeta; + private boolean uriEncodeLinkHref = true; public JsonApiLinksSerializer() { super(Links.class); @@ -56,6 +57,7 @@ public JsonApiLinksSerializer() { public void setJsonApiConfiguration(JsonApiConfiguration jsonApiConfiguration) { this.affordanceType = jsonApiConfiguration.getAffordancesRenderedAsLinkMeta(); this.removeHateoasLinkPropertiesFromMeta = jsonApiConfiguration.isJsonApi11LinkPropertiesRemovedFromLinkMeta(); + this.uriEncodeLinkHref = jsonApiConfiguration.isLinksUriEncoded(); } @Override @@ -82,7 +84,7 @@ public void serialize(Links value, JsonGenerator gen, SerializerProvider provide private void serializeLinkWithRelation(JsonGenerator gen, Link link) throws IOException { if (isSimpleLink(link)) { - gen.writeStringField(link.getRel().value(), UriUtils.encodeQuery(link.getHref(), StandardCharsets.UTF_8)); + gen.writeStringField(link.getRel().value(), uriEncodeLinkHref(link)); } else { gen.writeObjectFieldStart(link.getRel().value()); writeComplexLink(gen, link); @@ -91,7 +93,7 @@ private void serializeLinkWithRelation(JsonGenerator gen, Link link) throws IOEx } private void writeComplexLink(JsonGenerator gen, Link link) throws IOException { - gen.writeStringField("href", UriUtils.encodeQuery(link.getHref(), StandardCharsets.UTF_8)); + gen.writeStringField("href", uriEncodeLinkHref(link)); Map attributes = getAttributes(link); if (link.getTitle() != null) { gen.writeStringField("title", link.getTitle()); @@ -119,6 +121,10 @@ private boolean isSimpleLink(Link link) { return getAttributes(link).size() == 0; } + private String uriEncodeLinkHref(Link link) { + return uriEncodeLinkHref ? UriUtils.encodeQuery(link.getHref(), StandardCharsets.UTF_8) : link.getHref(); + } + private Map getAttributes(Link link) { final Map attributeMap = objectMapper.convertValue(link, Map.class);