package cn.jimmyshi.beanquery.selectors;
import java.beans.PropertyDescriptor;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Selector that use the bean properties as the key and the property values as
* the value. Because every object has a "class" property which is not required
* in most scenario, it will be excluded from the result. If you really want it,
* you can use the {@link #add(String...)} method to add it in the result map.
*/
public class ClassSelector extends KeyValueMapSelector {
private transient Logger logger = LoggerFactory.getLogger(ClassSelector.class);
private List<PropertySelector> propertySelectors = new LinkedList<PropertySelector>();
private CompositeSelector compositeSelector = new CompositeSelector();
/**
* @param clazz
* null will cause the select methods returning an empty Map or a
* list of Empty map as the result.
*/
public ClassSelector(Class<?> clazz) {
if (null == clazz) {
logger.warn("Input class is null");
return;
}
PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(clazz);
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
boolean propertyReadable = propertyDescriptor.getReadMethod() != null;
String propertyName = propertyDescriptor.getName();
// ignore the class property
if ("class".equals(propertyName)) {
continue;
}
if (propertyReadable) {
PropertySelector propertySelector = new PropertySelector(propertyDescriptor.getName());
propertySelectors.add(propertySelector);
compositeSelector.addSubSelector(propertySelector);
}
}
}
/**
* Exclude properties from the result map.
*/
public ClassSelector except(String... propertyNames) {
if(ArrayUtils.isEmpty(propertyNames)){
return this;
}
boolean updated = false;
for (String propertyToRemove : propertyNames) {
if (removePropertySelector(propertyToRemove)) {
updated = true;
}
}
if (updated) {
compositeSelector = new CompositeSelector(this.propertySelectors);
}
return this;
}
private boolean removePropertySelector(String propertyName) {
if (StringUtils.isBlank(propertyName)) {
return false;
}
for (PropertySelector selector : propertySelectors) {
if (selector.getProperty().equals(propertyName)) {
propertySelectors.remove(selector);
return true;
}
}
return false;
}
/**
* Include properties in the result map.
*/
public ClassSelector add(String... propertyNames) {
if (ArrayUtils.isNotEmpty(propertyNames)) {
for (String propertyNameToAdd : propertyNames) {
addPropertySelector(propertyNameToAdd);
}
}
return this;
}
private void addPropertySelector(String propertyNameToAdd) {
if (StringUtils.isBlank(propertyNameToAdd)) {
return;
}
for (PropertySelector propertySelector : propertySelectors) {
if (propertySelector.getProperty().equals(propertyNameToAdd)) {
return;
}
}
PropertySelector newPropertySelector = new PropertySelector(propertyNameToAdd);
propertySelectors.add(newPropertySelector);
compositeSelector.addSubSelector(newPropertySelector);
}
@Override
protected Map<String, Object> doSelect(Object item) {
return this.compositeSelector.select(item);
}
}