Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/main/java/com/github/jasminb/jsonapi/ResourceConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -812,7 +812,6 @@ private ObjectNode getDataNode(Object object, Map<String, ObjectNode> includedCo
// Cache the object for recursion breaking purposes
resourceCache.cache(resourceId.concat(configuration.getTypeName(object.getClass())), null);
}
dataNode.set(ATTRIBUTES, attributesNode);

// Handle relationships (remove from base type and add as relationships)
List<Field> relationshipFields = configuration.getRelationshipFields(object.getClass());
Expand Down Expand Up @@ -916,6 +915,20 @@ private ObjectNode getDataNode(Object object, Map<String, ObjectNode> includedCo
}
}

// Note: Attributes can be rendered once all other top
// level object properties have been removed.
// If done earlier, the presence of these properties
// will cause the isEmpty test to fail in the case
// of a configuration disallowing an empty
// 'attributes' tag to be rendered.
if (canSerializeEmptyAttributesTag(settings)) {
dataNode.set(ATTRIBUTES, attributesNode); // default
} else {
if (!attributesNode.isEmpty(null)) {
dataNode.set(ATTRIBUTES, attributesNode);
}
}

if (jsonLinks != null) {
dataNode.set(LINKS, jsonLinks);
}
Expand Down Expand Up @@ -1232,6 +1245,13 @@ private boolean shouldSerializeMeta(SerializationSettings settings) {
return serializationFeatures.contains(SerializationFeature.INCLUDE_META);
}

private boolean canSerializeEmptyAttributesTag(SerializationSettings settings) {
if (settings != null && settings.serializeEmptyAttributesTag() != null) {
return settings.serializeEmptyAttributesTag();
}
return serializationFeatures.contains(SerializationFeature.ATTRIBUTES_TAG_ONLY_IF_NOT_EMPTY);
}

private JsonNode removeField(ObjectNode node, Field field) {
if (field != null) {
return node.remove(namingStrategy.nameForField(null, null, field.getName()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,17 @@ public enum SerializationFeature {
/**
* If enabled, links attribute will be serialized
*/
INCLUDE_LINKS(true);
INCLUDE_LINKS(true),

/**
* If enabled, resources that only have
* type and id will not render the attributes property.
*/
ATTRIBUTES_TAG_ONLY_IF_NOT_EMPTY(false);

final boolean enabled;


SerializationFeature(boolean enabled) {
this.enabled = enabled;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public class SerializationSettings {
private List<String> relationshipExludes;
private Boolean serializeMeta;
private Boolean serializeLinks;
private Boolean serializeEmptyAttributesTag = true;

private SerializationSettings() {
// Hide CTOR
Expand Down Expand Up @@ -52,6 +53,10 @@ public Boolean serializeLinks() {
return serializeLinks;
}

public Boolean serializeEmptyAttributesTag() {
return serializeEmptyAttributesTag;
}

/**
* Serialisation settings builder.
*/
Expand All @@ -60,6 +65,7 @@ public static class Builder {
private List<String> relationshipExludes = new ArrayList<>();
private Boolean serializeMeta;
private Boolean serializeLinks;
private Boolean serializeEmptyAttributesTag;

/**
* Explicitly enable relationship serialisation.
Expand All @@ -70,7 +76,7 @@ public Builder includeRelationship(String relationshipName) {
relationshipIncludes.add(relationshipName);
return this;
}

/**
* Explicitly disable relationship serialisation.
* @param relationshipName {@link String} relationship name
Expand Down Expand Up @@ -100,6 +106,11 @@ public Builder serializeLinks(Boolean flag) {
serializeLinks = flag;
return this;
}

public Builder serializeEmptyAttributesTag(Boolean flag) {
serializeEmptyAttributesTag = flag;
return this;
}

/**
* Create new SerialisationSettings instance.
Expand All @@ -111,6 +122,7 @@ public SerializationSettings build() {
result.relationshipExludes = new ArrayList<>(relationshipExludes);
result.serializeLinks = serializeLinks;
result.serializeMeta = serializeMeta;
result.serializeEmptyAttributesTag = serializeEmptyAttributesTag;
return result;
}
}
Expand Down
29 changes: 25 additions & 4 deletions src/test/java/com/github/jasminb/jsonapi/SerializationTest.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package com.github.jasminb.jsonapi;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.github.jasminb.jsonapi.exceptions.DocumentSerializationException;
import com.github.jasminb.jsonapi.models.Article;
import com.github.jasminb.jsonapi.models.Author;
import com.github.jasminb.jsonapi.models.IntegerIdResource;
import com.github.jasminb.jsonapi.models.SimpleMeta;
import com.github.jasminb.jsonapi.models.SimpleResource;
import com.github.jasminb.jsonapi.models.Status;
import com.github.jasminb.jsonapi.models.User;
import com.github.jasminb.jsonapi.models.errors.Error;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand Down Expand Up @@ -127,6 +132,22 @@ public void testIncludedDataDisabledTroughSettings() throws DocumentSerializatio
Assert.assertNull(status.getContent());
}

@Test
public void testEnableNonEmptyAttributesTagThroughSettings() throws Exception {
SimpleResource source = new SimpleResource();
source.setId(80085);
JSONAPIDocument<SimpleResource> document = new JSONAPIDocument<>(source);

SerializationSettings serializationSettings = new SerializationSettings.Builder()
.serializeEmptyAttributesTag(false )
.build();

converter.registerType(SimpleResource.class);
String s = new String( converter.writeDocument(document, serializationSettings) );
ObjectMapper m = new ObjectMapper();
Assert.assertNull( m.readTree(s.getBytes()).get("attributes"));
}

/**
* Covers use-case where global settings are used to disable relationship attribute inclusion but
* behaviour is changed trouh local settings provided when serialization is executed.
Expand All @@ -136,18 +157,18 @@ public void testIncludedDataDisabledTroughSettings() throws DocumentSerializatio
public void testIncludedDataEnabledTroughSettings() throws DocumentSerializationException {
converter.disableSerializationOption(SerializationFeature.INCLUDE_RELATIONSHIP_ATTRIBUTES);
JSONAPIDocument<User> document = createDocument(createUser());

SerializationSettings serializationSettings = new SerializationSettings.Builder()
.includeRelationship("statuses")
.build();

JSONAPIDocument<User> convertedBack = converter.readDocument(
converter.writeDocument(document, serializationSettings), User.class);

Status status = convertedBack.get().getStatuses().iterator().next();
Assert.assertNotNull(status.getContent());
}

@Test
public void testOverrideGlobalMetaLinksSettings() throws DocumentSerializationException {
JSONAPIDocument<User> document = createDocument(createUser());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.github.jasminb.jsonapi.models;

import com.github.jasminb.jsonapi.IntegerIdHandler;
import com.github.jasminb.jsonapi.annotations.Id;
import com.github.jasminb.jsonapi.annotations.Type;

/**
* Model class used to test {@link Integer} as resource identifier.
*
* @author jbegic
*/
@Type("simple-resource-type")
public class SimpleResource {

@Id(IntegerIdHandler.class)
private Integer id;

public Integer getId() {
return id;
}

public void setId(Integer id) {
this.id = id;
}

}