in grails-converters/src/main/groovy/org/grails/web/converters/marshaller/json/DomainClassMarshaller.java [118:248]
public void marshalObject(Object value, JSON json) throws ConverterException {
JSONWriter writer = json.getWriter();
value = proxyHandler.unwrapIfProxy(value);
Class<?> clazz = value.getClass();
List<String> excludes = json.getExcludes(clazz);
List<String> includes = json.getIncludes(clazz);
IncludeExcludeSupport<String> includeExcludeSupport = new IncludeExcludeSupport<String>();
BeanWrapper beanWrapper = new BeanWrapperImpl(value);
writer.object();
if(includeClass && shouldInclude(includeExcludeSupport, includes, excludes, value, "class")) {
writer.key("class").value(clazz.getName());
}
PersistentEntity domainClass = findDomainClass(value);
if ( domainClass == null ) {
throw new GrailsConfigurationException("Could not retrieve the respective entity for domain " + value.getClass().getName() + " in the mapping context API");
}
PersistentProperty id = domainClass.getIdentity();
if(id != null) {
//Composite keys dont return an identity. They also do not render in the JSON.
//If using Composite keys, it may be advisable to use a customer Marshaller.
if(shouldInclude(includeExcludeSupport, includes, excludes, value, id.getName())) {
Object idValue = extractValue(value, id);
if(idValue != null) {
json.property(id.getName(), idValue);
}
}
}
if (shouldInclude(includeExcludeSupport, includes, excludes, value, GormProperties.VERSION) && isIncludeVersion()) {
PersistentProperty versionProperty = domainClass.getVersion();
Object version = extractValue(value, versionProperty);
if(version != null) {
json.property(GormProperties.VERSION, version);
}
}
List<PersistentProperty> properties = domainClass.getPersistentProperties();
for (PersistentProperty property : properties) {
if (property.equals(domainClass.getVersion())) {
continue;
}
if(!shouldInclude(includeExcludeSupport, includes, excludes, value, property.getName())) continue;
writer.key(property.getName());
if ( !(property instanceof Association) ) {
// Write non-relation property
Object val = beanWrapper.getPropertyValue(property.getName());
json.convertAnother(val);
}
else {
Object referenceObject = beanWrapper.getPropertyValue(property.getName());
if (isRenderDomainClassRelations()) {
if (referenceObject == null) {
writer.valueNull();
}
else {
referenceObject = proxyHandler.unwrapIfProxy(referenceObject);
if (referenceObject instanceof SortedMap) {
referenceObject = new TreeMap((SortedMap) referenceObject);
}
else if (referenceObject instanceof SortedSet) {
referenceObject = new TreeSet((SortedSet) referenceObject);
}
else if (referenceObject instanceof Set) {
referenceObject = new LinkedHashSet((Set) referenceObject);
}
else if (referenceObject instanceof Map) {
referenceObject = new LinkedHashMap((Map) referenceObject);
}
else if (referenceObject instanceof Collection) {
referenceObject = new ArrayList((Collection) referenceObject);
}
json.convertAnother(referenceObject);
}
}
else {
if (referenceObject == null) {
json.value(null);
}
else {
PersistentEntity referencedDomainClass = ((Association) property).getAssociatedEntity();
// Embedded are now always fully rendered
if (referencedDomainClass == null || ((Association)property).isEmbedded() || property.getType().isEnum()) {
json.convertAnother(referenceObject);
}
else if ( (property instanceof OneToOne) || (property instanceof ManyToOne)|| ((Association)property).isEmbedded()) {
asShortObject(referenceObject, json, referencedDomainClass.getIdentity(), referencedDomainClass);
}
else {
PersistentProperty referencedIdProperty = referencedDomainClass.getIdentity();
@SuppressWarnings("unused")
String refPropertyName = ((Association) property).getReferencedPropertyName();
if (referenceObject instanceof Collection) {
Collection o = (Collection) referenceObject;
writer.array();
for (Object el : o) {
asShortObject(el, json, referencedIdProperty, referencedDomainClass);
}
writer.endArray();
}
else if (referenceObject instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) referenceObject;
for (Map.Entry<Object, Object> entry : map.entrySet()) {
String key = String.valueOf(entry.getKey());
Object o = entry.getValue();
writer.object();
writer.key(key);
asShortObject(o, json, referencedIdProperty, referencedDomainClass);
writer.endObject();
}
}
}
}
}
}
}
writer.endObject();
}