io.katharsis.jackson.serializer.RelationshipContainerSerializer Maven / Gradle / Ivy
package io.katharsis.jackson.serializer;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import io.katharsis.jackson.exception.JsonSerializationException;
import io.katharsis.request.path.PathBuilder;
import io.katharsis.resource.field.ResourceField;
import io.katharsis.resource.registry.RegistryEntry;
import io.katharsis.resource.registry.ResourceRegistry;
import io.katharsis.response.ContainerType;
import io.katharsis.response.LinkageContainer;
import io.katharsis.response.RelationshipContainer;
import io.katharsis.utils.ClassUtils;
import io.katharsis.utils.Generics;
import io.katharsis.utils.PropertyUtils;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
/**
* Serializes a relationship inside of top-level links object
* Top-level Links.
*
* @see RelationshipContainer
*/
public class RelationshipContainerSerializer extends JsonSerializer {
private static final String SELF_FIELD_NAME = "self";
private static final String RELATED_FIELD_NAME = "related";
private static final String DATA_FIELD_NAME = "data";
private static final String LINKS_FIELD_NAME = "links";
private final ResourceRegistry resourceRegistry;
public RelationshipContainerSerializer(ResourceRegistry resourceRegistry) {
this.resourceRegistry = resourceRegistry;
}
@Override
public void serialize(RelationshipContainer relationshipContainer, JsonGenerator gen, SerializerProvider provider)
throws IOException {
gen.writeStartObject();
writeLinks(relationshipContainer, gen);
if ((!relationshipContainer.getRelationshipField().isLazy() &&
!relationshipContainer.getDataLinksContainer().getContainerType().equals(ContainerType.INCLUDED_NESTED)) ||
relationshipContainer.isForceInclusion()) {
writeLinkage(relationshipContainer, gen);
}
gen.writeEndObject();
}
private void writeLinks(RelationshipContainer relationshipContainer, JsonGenerator gen) throws IOException {
gen.writeFieldName(LINKS_FIELD_NAME);
gen.writeStartObject();
writeLink(relationshipContainer, gen, SELF_FIELD_NAME, true);
writeLink(relationshipContainer, gen, RELATED_FIELD_NAME, false);
gen.writeEndObject();
}
private void writeLink(RelationshipContainer relationshipContainer, JsonGenerator gen, String fieldName,
boolean addLinks) throws IOException {
Object data = relationshipContainer.getDataLinksContainer().getData();
Class> sourceClass = data.getClass();
String resourceUrl = resourceRegistry.getResourceUrl(sourceClass);
RegistryEntry entry = resourceRegistry.getEntry(sourceClass);
ResourceField idField = entry.getResourceInformation().getIdField();
Object sourceId = PropertyUtils.getProperty(data, idField.getUnderlyingName());
String url = resourceUrl + "/" + sourceId + (addLinks ? "/" + PathBuilder.RELATIONSHIP_MARK + "/" : "/")
+ relationshipContainer.getRelationshipField().getJsonName();
gen.writeStringField(fieldName, url);
}
/**
* Here it is needed to check actual generic type of a class. To achieve that {@code Class::getType} method cannot
* be used because of type erasure.
*
* @param relationshipContainer
* @param gen
* @throws IOException
*/
private void writeLinkage(RelationshipContainer relationshipContainer, JsonGenerator gen) throws IOException {
Class baseClass = relationshipContainer.getRelationshipField().getType();
Class relationshipClass = Generics
.getResourceClass(relationshipContainer.getRelationshipField().getGenericType(), baseClass);
RegistryEntry relationshipEntry = resourceRegistry.getEntry(relationshipClass);
gen.writeFieldName(DATA_FIELD_NAME);
writeLinkageField(relationshipContainer, gen, baseClass, relationshipEntry);
}
private void writeLinkageField(RelationshipContainer relationshipContainer, JsonGenerator gen, Class baseClass,
RegistryEntry relationshipEntry)
throws IOException {
try {
if (Iterable.class.isAssignableFrom(baseClass)) {
writeToManyLinkage(relationshipContainer, gen, relationshipEntry);
} else {
writeToOneLinkage(relationshipContainer, gen, relationshipEntry);
}
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new JsonSerializationException("Error writing linkage field");
}
}
private static void writeToManyLinkage(RelationshipContainer relationshipContainer, JsonGenerator gen,
RegistryEntry relationshipEntry)
throws IOException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
ResourceField relationshipField = relationshipContainer.getRelationshipField();
Object targetDataObj = PropertyUtils
.getProperty(relationshipContainer.getDataLinksContainer().getData(), relationshipField.getUnderlyingName());
gen.writeStartArray();
if (targetDataObj != null) {
for (Object objectItem : (Iterable) targetDataObj) {
Class> objectItemClass = ClassUtils.getJsonApiResourceClass(objectItem);
gen.writeObject(new LinkageContainer(objectItem, objectItemClass, relationshipEntry));
}
}
gen.writeEndArray();
}
private static void writeToOneLinkage(RelationshipContainer relationshipContainer, JsonGenerator gen,
RegistryEntry relationshipEntry)
throws IOException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
ResourceField relationshipField = relationshipContainer.getRelationshipField();
Object targetDataObj = PropertyUtils.getProperty(relationshipContainer.getDataLinksContainer().getData(), relationshipField.getUnderlyingName());
if (targetDataObj == null) {
gen.writeObject(null);
} else {
Class> targetDataObjClass = ClassUtils.getJsonApiResourceClass(targetDataObj);
gen.writeObject(new LinkageContainer(targetDataObj, targetDataObjClass, relationshipEntry));
}
}
public Class handledType() {
return RelationshipContainer.class;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy