1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 public class PropertyUtils {
34
35 private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>();
36 private final Map<Class<?>, Set<Property>> readableProperties = new HashMap<Class<?>, Set<Property>>();
37 private BeanAccess beanAccess = BeanAccess.DEFAULT;
38 private boolean allowReadOnlyProperties = false;
39 private boolean skipMissingProperties = 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 && skipMissingProperties) {
129 property = new MissingProperty(name);
130 }
131 if (property == null || !property.isWritable()) {
132 throw new YAMLException("Unable to find property '" + name + "' on class: "
133 + type.getName());
134 }
135 return property;
136 }
137
138 public void setBeanAccess(BeanAccess beanAccess) {
139 if (this.beanAccess != beanAccess) {
140 this.beanAccess = beanAccess;
141 propertiesCache.clear();
142 readableProperties.clear();
143 }
144 }
145
146 public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) {
147 if (this.allowReadOnlyProperties != allowReadOnlyProperties) {
148 this.allowReadOnlyProperties = allowReadOnlyProperties;
149 readableProperties.clear();
150 }
151 }
152
153
154
155
156
157
158
159
160 public void setSkipMissingProperties(boolean skipMissingProperties) {
161 if (this.skipMissingProperties != skipMissingProperties) {
162 this.skipMissingProperties = skipMissingProperties;
163 readableProperties.clear();
164 }
165 }
166 }