Open Source Repository

Home /json/flexjson-2.1 | Repository Home



flexjson/BeanAnalyzer.java
package flexjson;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

public class BeanAnalyzer {

    private static ThreadLocal<Map<Class,BeanAnalyzer>> cache = new ThreadLocal<Map<Class,BeanAnalyzer>>();

    private Class clazz;
    private BeanAnalyzer superBean;
    private Map<String,BeanProperty> properties;

    public static BeanAnalyzer analyze( Class clazz ) {
        if( cache.get() == null ) cache.set( new HashMap<Class,BeanAnalyzer>() );
        if( clazz == null ) return null;
        if( !cache.get().containsKey(clazz) ) {
            cache.get().put( clazz, new BeanAnalyzer(clazz) );
        }
        return cache.get().get( clazz );
    }

    public static void clearCache() {
        cache.remove();
    }

    protected BeanAnalyzer(Class clazz) {
        this.clazz = clazz;
        superBean = analyze( clazz.getSuperclass() );
        populateProperties();
    }

    private void populateProperties() {
        properties = new TreeMap<String,BeanProperty>();
        for( Method method : clazz.getDeclaredMethods() ) {
            int modifiers = method.getModifiers();
            if( Modifier.isStatic(modifiers) ) continue;

            int numberOfArgs = method.getParameterTypes().length;
            String name = method.getName();
            if( name.length() <= 3 && !name.startsWith("is") ) continue;
            
            if( numberOfArgs == 0 ) {
                if( name.startsWith("get") ) {
                    String property = uncapitalize( name.substring(3) );
                    if( !properties.containsKey( property ) ) {
                        properties.put( property, new BeanProperty(property, this) );
                    }
                    properties.get( property ).setReadMethod( method );
                } else if( name.startsWith("is") ) {
                    String property = uncapitalize( name.substring(2) );
                    if( !properties.containsKey( property ) ) {
                        properties.put( property, new BeanProperty(property, this) );
                    }
                    properties.get( property ).setReadMethod(method);
                }
            } else if( numberOfArgs == 1 ) {
                if( name.startsWith("set") ) {
                    String property = uncapitalize( name.substring(3) );
                    if( !properties.containsKey( property ) ) {
                        properties.put( property, new BeanProperty(property, this) );
                    }
                    properties.get( property ).addWriteMethod(method);
                }
            }
        }

        for( Field publicProperties : clazz.getFields() ) {
            int modifiers = publicProperties.getModifiers();
            if( Modifier.isStatic( modifiers ) || Modifier.isTransient(modifiers) ) continue;
            if( !properties.containsKey( publicProperties.getName() ) ) {
                properties.put( publicProperties.getName(), new BeanProperty( publicProperties, this ) );
            }
        }
    }

    public BeanAnalyzer getSuperBean() {
        return superBean;
    }

    private String uncapitalize( String value ) {
        if( value.length() < 2 ) {
             return value.toLowerCase();
        } else if( Character.isUpperCase(value.charAt(0)) && Character.isUpperCase(value.charAt(1)) ) {
            return value;
        } else {
            return Character.toLowerCase( value.charAt(0) ) + value.substring(1);
        }
    }

    public BeanProperty getProperty(String name) {
        BeanAnalyzer current = this;
        while( current != null ) {
            BeanProperty property = current.properties.get( name );
            if( property != null ) return property;
            current = current.superBean;
        }
        return null;
    }

    public Collection<BeanProperty> getProperties() {
        Map<String,BeanProperty> properties = new TreeMap<String,BeanProperty>(this.properties);
        BeanAnalyzer current = this.superBean;
        while( current != null ) {
            merge( properties, current.properties );
            current = current.superBean;
        }
        return properties.values();
    }

    private void merge(Map<String, BeanProperty> destination, Map<String, BeanProperty> source) {
        for( String key : source.keySet() ) {
            if( !destination.containsKey( key ) ) {
                destination.put( key, source.get(key) );
            }
        }
    }

    public boolean hasProperty(String name) {
        return properties.containsKey(name);
    }

    protected Field getDeclaredField(String name) {
        try {
            return clazz.getDeclaredField( name );
        } catch (NoSuchFieldException e) {
            // ignore field does not exist.
            return null;
        }
    }
}