View Javadoc

    1   /**
    2    * Copyright (c) 2008-2011, http://www.snakeyaml.org
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package org.yaml.snakeyaml.introspector;
    18
    19  import java.beans.IntrospectionException;
    20  import java.beans.Introspector;
    21  import java.beans.PropertyDescriptor;
    22  import java.lang.reflect.Field;
    23  import java.lang.reflect.Method;
    24  import java.lang.reflect.Modifier;
    25  import java.util.Collection;
    26  import java.util.HashMap;
    27  import java.util.LinkedHashMap;
    28  import java.util.Map;
    29  import java.util.Set;
    30  import java.util.TreeSet;
    31
    32  import org.yaml.snakeyaml.error.YAMLException;
    33
    34  public class PropertyUtils {
    35
    36      private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>();
    37      private final Map<Class<?>, Set<Property>> readableProperties = new HashMap<Class<?>, Set<Property>>();
    38      private BeanAccess beanAccess = BeanAccess.DEFAULT;
    39      private boolean allowReadOnlyProperties = false;
    40
    41      protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess)
    42              throws IntrospectionException {
    43          if (propertiesCache.containsKey(type)) {
    44              return propertiesCache.get(type);
    45          }
    46
    47          Map<String, Property> properties = new LinkedHashMap<String, Property>();
    48          boolean inaccessableFieldsExist = false;
    49          switch (bAccess) {
    50          case FIELD:
    51              for (Class<?> c = type; c != null; c = c.getSuperclass()) {
    52                  for (Field field : c.getDeclaredFields()) {
    53                      int modifiers = field.getModifiers();
    54                      if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)
    55                              && !properties.containsKey(field.getName())) {
    56                          properties.put(field.getName(), new FieldProperty(field));
    57                      }
    58                  }
    59              }
    60              break;
    61          default:
    62              // add JavaBean properties
    63              for (PropertyDescriptor property : Introspector.getBeanInfo(type)
    64                      .getPropertyDescriptors()) {
    65                  Method readMethod = property.getReadMethod();
    66                  if (readMethod == null || !readMethod.getName().equals("getClass")) {
    67                      properties.put(property.getName(), new MethodProperty(property));
    68                  }
    69              }
    70
    71              // add public fields
    72              for (Class<?> c = type; c != null; c = c.getSuperclass()) {
    73                  for (Field field : c.getDeclaredFields()) {
    74                      int modifiers = field.getModifiers();
    75                      if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
    76                          if (Modifier.isPublic(modifiers)) {
    77                              properties.put(field.getName(), new FieldProperty(field));
    78                          } else {
    79                              inaccessableFieldsExist = true;
    80                          }
    81                      }
    82                  }
    83              }
    84              break;
    85          }
    86          if (properties.isEmpty() && inaccessableFieldsExist) {
    87              throw new YAMLException("No JavaBean properties found in " + type.getName());
    88          }
    89          propertiesCache.put(type, properties);
    90          return properties;
    91      }
    92
    93      public Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException {
    94          return getProperties(type, beanAccess);
    95      }
    96
    97      public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess)
    98              throws IntrospectionException {
    99          if (readableProperties.containsKey(type)) {
    100             return readableProperties.get(type);
    101         }
    102         Set<Property> properties = createPropertySet(type, bAccess);
    103         readableProperties.put(type, properties);
    104         return properties;
    105     }
    106
    107     protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess)
    108             throws IntrospectionException {
    109         Set<Property> properties = new TreeSet<Property>();
    110         Collection<Property> props = getPropertiesMap(type, bAccess).values();
    111         for (Property property : props) {
    112             if (property.isReadable() && (allowReadOnlyProperties || property.isWritable())) {
    113                 properties.add(property);
    114             }
    115         }
    116         return properties;
    117     }
    118
    119     public Property getProperty(Class<? extends Object> type, String name)
    120             throws IntrospectionException {
    121         return getProperty(type, name, beanAccess);
    122     }
    123
    124     public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess)
    125             throws IntrospectionException {
    126         Map<String, Property> properties = getPropertiesMap(type, bAccess);
    127         Property property = properties.get(name);
    128         if (property == null || !property.isWritable()) {
    129             throw new YAMLException("Unable to find property '" + name + "' on class: "
    130                     + type.getName());
    131         }
    132         return property;
    133     }
    134
    135     public void setBeanAccess(BeanAccess beanAccess) {
    136         if (this.beanAccess != beanAccess) {
    137             this.beanAccess = beanAccess;
    138             propertiesCache.clear();
    139             readableProperties.clear();
    140         }
    141     }
    142
    143     public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) {
    144         if (this.allowReadOnlyProperties != allowReadOnlyProperties) {
    145             this.allowReadOnlyProperties = allowReadOnlyProperties;
    146             readableProperties.clear();
    147         }
    148     }
    149 }