1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
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 }