Skip to content

Commit

Permalink
feat: allow to opt out links uri encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
jimirocks committed Aug 12, 2024
1 parent e1cc5b4 commit a56af9e
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 3 deletions.
1 change: 1 addition & 0 deletions lib/src/main/asciidoc/configuration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
| LinksNotUrlEncoded | Set of links' rels which are not URL encoded when serializing. Empty by default. | empty set
|===

TIP: Since the JSON:API recommendation contains square brackets in the request parameter names,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.With;
import org.springframework.hateoas.LinkRelation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;


Expand Down Expand Up @@ -262,6 +265,19 @@ public enum AffordanceType {
@Getter
private final boolean jsonApiCompliantLinks;

/**
* By default, JSON:API links are serialized as URL encoded.
*
* If you set this configuration, Spring HATEOAS links with set relations 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
* URL encoded.
* @param linksNotUrlEncoded The new value of this configuration's linksNotUrlEncoded
* @return The default is empty set.
*/
@With
@Getter
private final Set<LinkRelation> linksNotUrlEncoded;

@With(AccessLevel.PRIVATE)
private final Map<Class<?>, String> typeForClass;

Expand Down Expand Up @@ -361,8 +377,8 @@ public JsonApiConfiguration() {
this.affordancesRenderedAsLinkMeta = AffordanceType.NONE;
this.jsonApi11LinkPropertiesRemovedFromLinkMeta = true;
this.jsonApiCompliantLinks = true;
this.linksNotUrlEncoded = new HashSet<>();
this.objectMapperCustomizer = customObjectMapper -> {
}; // Default to no action.
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY;
import static com.toedter.spring.hateoas.jsonapi.MediaTypes.JSON_API;
Expand All @@ -47,6 +49,7 @@ class JsonApiLinksSerializer extends AbstractJsonApiSerializer<Links> {
private static final ObjectMapper objectMapper = new ObjectMapper();
private JsonApiConfiguration.AffordanceType affordanceType;
private boolean removeHateoasLinkPropertiesFromMeta;
private Set<LinkRelation> linksNotUrlEncoded = new HashSet<>();

public JsonApiLinksSerializer() {
super(Links.class);
Expand All @@ -56,6 +59,7 @@ public JsonApiLinksSerializer() {
public void setJsonApiConfiguration(JsonApiConfiguration jsonApiConfiguration) {
this.affordanceType = jsonApiConfiguration.getAffordancesRenderedAsLinkMeta();
this.removeHateoasLinkPropertiesFromMeta = jsonApiConfiguration.isJsonApi11LinkPropertiesRemovedFromLinkMeta();
this.linksNotUrlEncoded = jsonApiConfiguration.getLinksNotUrlEncoded();
}

@Override
Expand All @@ -82,7 +86,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);
Expand All @@ -91,7 +95,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<String, Object> attributes = getAttributes(link);
if (link.getTitle() != null) {
gen.writeStringField("title", link.getTitle());
Expand Down Expand Up @@ -119,6 +123,10 @@ private boolean isSimpleLink(Link link) {
return getAttributes(link).size() == 0;
}

private String uriEncodeLinkHref(Link link) {
return linksNotUrlEncoded.contains(link.getRel()) ? link.getHref() : UriUtils.encodeQuery(link.getHref(), StandardCharsets.UTF_8);
}


private Map<String, Object> getAttributes(Link link) {
final Map<String, Object> attributeMap = objectMapper.convertValue(link, Map.class);
Expand Down

0 comments on commit a56af9e

Please sign in to comment.