package org.openstack.atlas.api.helpers.JsonSerializer;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializationConfig;
import org.codehaus.jackson.map.SerializerProvider;
import org.codehaus.jackson.map.introspect.BasicBeanDescription;
import org.codehaus.jackson.map.ser.CustomSerializerFactory;
import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.JavaType;
import org.openstack.atlas.api.helpers.reflection.ClassReflectionTools;
import org.openstack.atlas.api.helpers.reflection.ClassReflectionToolsException;
import java.io.IOException;
import java.util.GregorianCalendar;
import java.util.List;
/**
* This serializer overrides any custom serializers defined for types via a
* CustomSerializerFactory (or similar) and uses the BeanSerializerFactory for
* serializing types. It also creates a clean SerializerProvider, which ensures
* that any previously registered custom serializers are not used. This
* particular serializer is really valuable when you want collections to be
* serialized naturally and single objects to be serialized differently (e.g.
* with a wrapper).
* <p/>
* Optionally, a wrapperFieldName can be supplied that will be used to write a
* wrapping object around the JSON output.
*/
public class PropertyCollectionSerializer extends JsonSerializer<Object> {
private SerializationConfig config;
private String wrapperFieldName;
private String getterName;
private Boolean hasLinks = false;
public PropertyCollectionSerializer(SerializationConfig config, Class someClass, String getterName) {
this.config = config;
this.wrapperFieldName = (someClass == null) ? null : ClassReflectionTools.getXmlRootElementName(someClass);
this.getterName = getterName;
}
public PropertyCollectionSerializer(SerializationConfig config, Class someClass, String getterName, Boolean links) {
this.config = config;
this.wrapperFieldName = (someClass == null) ? null : ClassReflectionTools.getXmlRootElementName(someClass);
this.getterName = getterName;
this.hasLinks = links;
}
@Override
public void serialize(Object value, JsonGenerator jgen, SerializerProvider sp) throws IOException {
String valClassName = value.getClass().getName();
List propList;
try {
propList = (List) ClassReflectionTools.invokeGetter(value, getterName);
} catch (ClassReflectionToolsException ex) {
String format = "Error Failed to dynamically invoke %s.%s() during serialization of %s";
String errMsg = String.format(format, valClassName, getterName, value.toString());
throw new org.codehaus.jackson.JsonGenerationException(errMsg, ex);
}
CustomSerializerFactory csf = new CustomSerializerFactory();
csf.addSpecificMapping(GregorianCalendar.class, new DateTimeSerializer(config, null));
if (this.wrapperFieldName != null) {
jgen.writeStartObject();
jgen.writeFieldName(this.wrapperFieldName);
writeJsonArray(jgen, propList, true);
} else {
writeJsonArray(jgen, propList, false);
}
if (hasLinks) {
writeLinks(value, jgen, valClassName);
}
if (wrapperFieldName != null) {
jgen.writeEndObject();
}
}
private void writeLinks(Object value, JsonGenerator jgen, String valClassName) throws IOException {
List propList;
String format;
String errMsg;
String linksGetMethod = "getLinks";
try {
propList = (List) ClassReflectionTools.invokeGetter(value, linksGetMethod);
} catch (ClassReflectionToolsException ex) {
format = "Error Failed to dynamically invoke %s.%s() during serialization of %s";
errMsg = String.format(format, valClassName, linksGetMethod, value.toString());
throw new org.codehaus.jackson.JsonGenerationException(errMsg, ex);
}
writeJsonArrayWithFieldName(jgen, propList, false, "links");
}
private void writeJsonArray(JsonGenerator jgen, List propList, boolean writeWhenNullOrEmpty) throws IOException {
if (propList != null && !propList.isEmpty()) {
jgen.writeStartArray();
for (Object childObj : propList) {
childSerialize(childObj, jgen);
}
jgen.writeEndArray();
} else if (writeWhenNullOrEmpty) {
jgen.writeStartArray();
jgen.writeEndArray();
}
}
private void writeJsonArrayWithFieldName(JsonGenerator jgen, List propList, boolean writeWhenNullOrEmpty, String fieldName) throws IOException {
if (writeWhenNullOrEmpty || !propList.isEmpty()) jgen.writeFieldName(fieldName);
writeJsonArray(jgen, propList, writeWhenNullOrEmpty);
}
// Cause I kept getting confused when this was done in the serializer method directly
private void childSerialize(Object obj, JsonGenerator jgen) throws JsonProcessingException, IOException {
SerializerProviderBuilder providerBuilder = new SerializerProviderBuilder();
//BeanSerializerFactory csf = BeanSerializerFactory.instance;
CustomSerializerFactory csf = new CustomSerializerFactory();
csf.addSpecificMapping(GregorianCalendar.class, new DateTimeSerializer(config, null));
SerializerProvider childProvider;
JavaType childType = TypeFactory.type(obj.getClass());
BasicBeanDescription childBeanDesc = this.config.introspect(childType);
JsonSerializer<Object> childSerializer = csf.findBeanSerializer(childType, config, childBeanDesc);
childProvider = providerBuilder.createProvider(config, csf);
childSerializer.serialize(obj, jgen, childProvider);
}
}