Coverage Report - org.yaml.snakeyaml.introspector.PropertyUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
PropertyUtils
100%
65/65
98%
57/58
4.667
PropertyUtils$1
100%
1/1
N/A
4.667
 
 1  
 /**
 2  
  * Copyright (c) 2008-2012, 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  
 package org.yaml.snakeyaml.introspector;
 17  
 
 18  
 import java.beans.IntrospectionException;
 19  
 import java.beans.Introspector;
 20  
 import java.beans.PropertyDescriptor;
 21  
 import java.lang.reflect.Field;
 22  
 import java.lang.reflect.Method;
 23  
 import java.lang.reflect.Modifier;
 24  
 import java.util.Collection;
 25  
 import java.util.HashMap;
 26  
 import java.util.LinkedHashMap;
 27  
 import java.util.Map;
 28  
 import java.util.Set;
 29  
 import java.util.TreeSet;
 30  
 
 31  
 import org.yaml.snakeyaml.error.YAMLException;
 32  
 
 33  132937
 public class PropertyUtils {
 34  
 
 35  132937
     private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>();
 36  132937
     private final Map<Class<?>, Set<Property>> readableProperties = new HashMap<Class<?>, Set<Property>>();
 37  132937
     private BeanAccess beanAccess = BeanAccess.DEFAULT;
 38  132937
     private boolean allowReadOnlyProperties = false;
 39  132937
     private boolean skipMissingProperties = false;
 40  
 
 41  
     protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess)
 42  
             throws IntrospectionException {
 43  14880
         if (propertiesCache.containsKey(type)) {
 44  2346
             return propertiesCache.get(type);
 45  
         }
 46  
 
 47  12534
         Map<String, Property> properties = new LinkedHashMap<String, Property>();
 48  12534
         boolean inaccessableFieldsExist = false;
 49  12534
         switch (bAccess) {
 50  
         case FIELD:
 51  90
             for (Class<?> c = type; c != null; c = c.getSuperclass()) {
 52  127
                 for (Field field : c.getDeclaredFields()) {
 53  67
                     int modifiers = field.getModifiers();
 54  67
                     if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)
 55  
                             && !properties.containsKey(field.getName())) {
 56  61
                         properties.put(field.getName(), new FieldProperty(field));
 57  
                     }
 58  
                 }
 59  
             }
 60  30
             break;
 61  
         default:
 62  
             // add JavaBean properties
 63  
             for (PropertyDescriptor property : Introspector.getBeanInfo(type)
 64  26285
                     .getPropertyDescriptors()) {
 65  13781
                 Method readMethod = property.getReadMethod();
 66  13781
                 if (readMethod == null || !readMethod.getName().equals("getClass")) {
 67  1277
                     properties.put(property.getName(), new MethodProperty(property));
 68  
                 }
 69  
             }
 70  
 
 71  
             // add public fields
 72  37569
             for (Class<?> c = type; c != null; c = c.getSuperclass()) {
 73  83524
                 for (Field field : c.getDeclaredFields()) {
 74  58459
                     int modifiers = field.getModifiers();
 75  58459
                     if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) {
 76  58435
                         if (Modifier.isPublic(modifiers)) {
 77  57151
                             properties.put(field.getName(), new FieldProperty(field));
 78  
                         } else {
 79  1284
                             inaccessableFieldsExist = true;
 80  
                         }
 81  
                     }
 82  
                 }
 83  
             }
 84  
             break;
 85  
         }
 86  12534
         if (properties.isEmpty() && inaccessableFieldsExist) {
 87  4
             throw new YAMLException("No JavaBean properties found in " + type.getName());
 88  
         }
 89  12530
         propertiesCache.put(type, properties);
 90  12530
         return properties;
 91  
     }
 92  
 
 93  
     public Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException {
 94  45033
         return getProperties(type, beanAccess);
 95  
     }
 96  
 
 97  
     public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess)
 98  
             throws IntrospectionException {
 99  45033
         if (readableProperties.containsKey(type)) {
 100  32758
             return readableProperties.get(type);
 101  
         }
 102  12275
         Set<Property> properties = createPropertySet(type, bAccess);
 103  12271
         readableProperties.put(type, properties);
 104  12271
         return properties;
 105  
     }
 106  
 
 107  
     protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess)
 108  
             throws IntrospectionException {
 109  12274
         Set<Property> properties = new TreeSet<Property>();
 110  12274
         Collection<Property> props = getPropertiesMap(type, bAccess).values();
 111  12270
         for (Property property : props) {
 112  57710
             if (property.isReadable() && (allowReadOnlyProperties || property.isWritable())) {
 113  57695
                 properties.add(property);
 114  
             }
 115  
         }
 116  12270
         return properties;
 117  
     }
 118  
 
 119  
     public Property getProperty(Class<? extends Object> type, String name)
 120  
             throws IntrospectionException {
 121  2605
         return getProperty(type, name, beanAccess);
 122  
     }
 123  
 
 124  
     public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess)
 125  
             throws IntrospectionException {
 126  2605
         Map<String, Property> properties = getPropertiesMap(type, bAccess);
 127  2605
         Property property = properties.get(name);
 128  2605
         if (property == null && skipMissingProperties) {
 129  2
             property = new MissingProperty(name);
 130  
         }
 131  2605
         if (property == null || !property.isWritable()) {
 132  15
             throw new YAMLException("Unable to find property '" + name + "' on class: "
 133  
                     + type.getName());
 134  
         }
 135  2590
         return property;
 136  
     }
 137  
 
 138  
     public void setBeanAccess(BeanAccess beanAccess) {
 139  47
         if (this.beanAccess != beanAccess) {
 140  21
             this.beanAccess = beanAccess;
 141  21
             propertiesCache.clear();
 142  21
             readableProperties.clear();
 143  
         }
 144  47
     }
 145  
 
 146  
     public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) {
 147  132936
         if (this.allowReadOnlyProperties != allowReadOnlyProperties) {
 148  13
             this.allowReadOnlyProperties = allowReadOnlyProperties;
 149  13
             readableProperties.clear();
 150  
         }
 151  132936
     }
 152  
 
 153  
     /**
 154  
      * Skip properties that are missing during deserialization of YAML to a Java
 155  
      * object. The default is false.
 156  
      * 
 157  
      * @param skipMissingProperties
 158  
      *            true if missing properties should be skipped, false otherwise.
 159  
      */
 160  
     public void setSkipMissingProperties(boolean skipMissingProperties) {
 161  2
         if (this.skipMissingProperties != skipMissingProperties) {
 162  1
             this.skipMissingProperties = skipMissingProperties;
 163  1
             readableProperties.clear();
 164  
         }
 165  2
     }
 166  
 }