001package ch.qos.logback.core.joran.util.beans;
002
003import java.lang.reflect.Method;
004import java.util.HashMap;
005import java.util.Map;
006
007import ch.qos.logback.core.Context;
008import ch.qos.logback.core.spi.ContextAwareBase;
009
010/**
011 * Encapsulates creation of {@link BeanDescription} instances. This factory is
012 * kind of a lightweight Introspector as described in the Java Beans API
013 * specification. The given class is only analyzed for its public getters,
014 * setters and adders methods. Implementations of the BeanInfo interface are not
015 * taken into account for analysis. Therefore this class is only partially
016 * compatible with the Java Beans API specification.
017 *
018 *
019 * @author urechm
020 */
021public class BeanDescriptionFactory extends ContextAwareBase {
022
023    BeanDescriptionFactory(Context context) {
024        setContext(context);
025    }
026
027    /**
028     *
029     * @param clazz to create a {@link BeanDescription} for.
030     * @return a {@link BeanDescription} for the given class.
031     */
032    public BeanDescription create(Class<?> clazz) {
033        Map<String, Method> propertyNameToGetter = new HashMap<String, Method>();
034        Map<String, Method> propertyNameToSetter = new HashMap<String, Method>();
035        Map<String, Method> propertyNameToAdder = new HashMap<String, Method>();
036        Method[] methods = clazz.getMethods();
037        for (Method method : methods) {
038            if (method.isBridge()) {
039                // we can safely ignore bridge methods
040                continue;
041            }
042            if (BeanUtil.isGetter(method)) {
043                String propertyName = BeanUtil.getPropertyName(method);
044                Method oldGetter = propertyNameToGetter.put(propertyName, method);
045                if (oldGetter != null) {
046                    if (oldGetter.getName().startsWith(BeanUtil.PREFIX_GETTER_IS)) {
047                        propertyNameToGetter.put(propertyName, oldGetter);
048                    }
049                    String message = String.format("Class '%s' contains multiple getters for the same property '%s'.",
050                            clazz.getCanonicalName(), propertyName);
051                    addWarn(message);
052                }
053            } else if (BeanUtil.isSetter(method)) {
054                String propertyName = BeanUtil.getPropertyName(method);
055                Method oldSetter = propertyNameToSetter.put(propertyName, method);
056                if (oldSetter != null) {
057                    String message = String.format("Class '%s' contains multiple setters for the same property '%s'.",
058                            clazz.getCanonicalName(), propertyName);
059                    addWarn(message);
060                }
061            } else if (BeanUtil.isAdder(method)) {
062                String propertyName = BeanUtil.getPropertyName(method);
063                Method oldAdder = propertyNameToAdder.put(propertyName, method);
064                if (oldAdder != null) {
065                    String message = String.format("Class '%s' contains multiple adders for the same property '%s'.",
066                            clazz.getCanonicalName(), propertyName);
067                    addWarn(message);
068                }
069            }
070        }
071        return new BeanDescription(clazz, propertyNameToGetter, propertyNameToSetter, propertyNameToAdder);
072    }
073}