package net.eusashead.bjugquerydsl.hateoas;
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.util.UriTemplate;
import com.theoryinpractise.halbuilder.api.Representation;
import com.theoryinpractise.halbuilder.api.RepresentationFactory;
public class RepresentationConverterImpl implements RepresentationConverter {
private final RepresentationFactory representationFactory;
private final List<ResourceMetadataExtractor> extractors = new ArrayList<ResourceMetadataExtractor>();
private final SimplePropertyConverter simplePropertyConverter;
public RepresentationConverterImpl(RepresentationFactory representationFactory, SimplePropertyConverter simplePropertyConverter) {
this.representationFactory = representationFactory;
this.simplePropertyConverter = simplePropertyConverter;
}
public void registerExtractor(ResourceMetadataExtractor extractor) {
this.extractors.add(extractor);
}
/* (non-Javadoc)
* @see net.eusashead.bjugquerydsl.hateoas.RepresentationConverter#convert(java.lang.Object)
*/
@Override
public Representation convert(Object bean) {
return convert(bean, null, true);
}
/* (non-Javadoc)
* @see net.eusashead.bjugquerydsl.hateoas.RepresentationConverter#convert(java.lang.Object, java.lang.String)
*/
@Override
public Representation convert(Object bean, String...properties) {
return convert(bean, null, true, properties);
}
/* (non-Javadoc)
* @see net.eusashead.bjugquerydsl.hateoas.RepresentationConverter#convert(java.lang.Object, org.springframework.web.util.UriTemplate, java.lang.String)
*/
@Override
public Representation convert(Object bean, UriTemplate uriTemplate, String...properties) {
return convert(bean, uriTemplate, true, properties);
}
private Representation convert(Object bean, UriTemplate uriTemplate,
boolean recursive, String... properties) {
// Validate arguments
if (bean == null) {
throw new IllegalArgumentException("Cannot pass null bean to convert()");
}
Class<?> target = bean.getClass();
// Get the ResourceMetadataExtractor
ResourceMetadataExtractor extractor = findMatchingExtractor(target);
// Get the metadata
ResourceMetadata metadata = extractor.extract(target);
// Get the URI template from metadata or argument
uriTemplate = uriTemplate != null ? uriTemplate : metadata.getUriTemplate();
// Get the URI from the template
String uri = null;
if (uriTemplate != null) {
uri = uriTemplate.expand(metadata.getUriVariables(bean)).toString();
}
// Create the representation
Representation representation = representationFactory.newRepresentation(uri);
// Determine the scope
List<Property> scope;
if (properties == null || properties.length == 0) {
scope = metadata.getAllProperties();
} else {
scope = metadata.getPropertiesByName(properties);
}
// Copy the properties
for (Property property : scope) {
// Get the property value
Object value = property.getValue(bean);
// Copy if not null
if (value != null) {
// Is it an embedded resource or a property
if (EmbeddedResource.class.isAssignableFrom(property.getClass())) {
// Only copy embedded if recursive
if (recursive) {
// Add the embedded resource
EmbeddedResource embedded = EmbeddedResource.class.cast(property);
addRepresentation(representation, embedded.getName(), embedded.getUriTemplate(), value);
}
} else {
// It's a simple property, add it
addProperty(representation, property.getName(), value);
}
}
}
return representation;
}
/**
* Find a {@link ResourceMetadataExtractor}
* that can extract {@link ResourceMetadata}
* for the given {@link Class}
* @param target
* @return
*/
private ResourceMetadataExtractor findMatchingExtractor(
Class<? extends Object> target) {
for (ResourceMetadataExtractor extractor : extractors) {
if (extractor.canExtract(target)) {
return extractor;
}
}
throw new RuntimeException(String.format("No matching ResourceMetadataExtractor for class %s", target));
}
/* (non-Javadoc)
* @see net.eusashead.bjugquerydsl.hateoas.RepresentationConverter#addProperty(com.theoryinpractise.halbuilder.api.Representation, java.lang.String, java.lang.Object)
*/
@Override
public void addProperty(Representation representation, String name, Object value) {
if (SimplePropertyUtil.isSimpleProperty(value.getClass())) {
Object converted = simplePropertyConverter.convert(value, String.class);
representation.withProperty(name, converted);
} else {
throw new IllegalArgumentException(String.format("Property %s of type %s is not a simple property", name, value.getClass()));
}
}
/* (non-Javadoc)
* @see net.eusashead.bjugquerydsl.hateoas.RepresentationConverter#addRepresentation(com.theoryinpractise.halbuilder.api.Representation, java.lang.String, java.lang.Object)
*/
@Override
public void addRepresentation(Representation representation, String rel, Object value) {
addRepresentation(representation, rel, null, value);
}
/* (non-Javadoc)
* @see net.eusashead.bjugquerydsl.hateoas.RepresentationConverter#addRepresentation(com.theoryinpractise.halbuilder.api.Representation, java.lang.String, org.springframework.web.util.UriTemplate, java.lang.Object)
*/
@Override
public void addRepresentation(Representation representation, String rel, UriTemplate uriTemplate, Object value) {
if (!SimplePropertyUtil.isSimpleProperty(value.getClass())) {
// Handle collections
if (Iterable.class.isAssignableFrom(value.getClass())) {
for (Object obj : Iterable.class.cast(value)) {
// Create a representation
Representation child = this.convert(obj, uriTemplate, false);
representation.withRepresentation(rel, child);
}
} else {
// Create a representation
Representation child = this.convert(value, uriTemplate, false);
representation.withRepresentation(rel, child);
}
} else {
throw new IllegalArgumentException(String.format("Property %s of type %s is not a representation type", rel, value.getClass()));
}
}
}