/** * Copyright (c) 2008-2013, http://www.snakeyaml.org * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.yaml.snakeyaml.introspector; //import java.beans.IntrospectionException; //import java.beans.Introspector; //import java.beans.PropertyDescriptor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.yaml.snakeyaml.error.YAMLException; public class PropertyUtils { private final Map<Class<?>, Map<String, Property>> propertiesCache = new HashMap<Class<?>, Map<String, Property>>(); private final Map<Class<?>, Set<Property>> readableProperties = new HashMap<Class<?>, Set<Property>>(); private BeanAccess beanAccess = BeanAccess.DEFAULT; private boolean allowReadOnlyProperties = false; private boolean skipMissingProperties = false; // protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess) // throws IntrospectionException { protected Map<String, Property> getPropertiesMap(Class<?> type, BeanAccess bAccess) { if (propertiesCache.containsKey(type)) { return propertiesCache.get(type); } Map<String, Property> properties = new LinkedHashMap<String, Property>(); // boolean inaccessableFieldsExist = false; // switch (bAccess) { // case FIELD: // for (Class<?> c = type; c != null; c = c.getSuperclass()) { // for (Field field : c.getDeclaredFields()) { // int modifiers = field.getModifiers(); // if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers) // && !properties.containsKey(field.getName())) { // properties.put(field.getName(), new FieldProperty(field)); // } for (Class<?> c = type; c != null; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { int modifiers = field.getModifiers(); if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers) && !properties.containsKey(field.getName())) { properties.put(field.getName(), new FieldProperty(field)); } } // break; // default: // // add JavaBean properties // for (PropertyDescriptor property : Introspector.getBeanInfo(type) // .getPropertyDescriptors()) { // Method readMethod = property.getReadMethod(); // if (readMethod == null || !readMethod.getName().equals("getClass")) { // properties.put(property.getName(), new MethodProperty(property)); // } // } } // // add public fields // for (Class<?> c = type; c != null; c = c.getSuperclass()) { // for (Field field : c.getDeclaredFields()) { // int modifiers = field.getModifiers(); // if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers)) { // if (Modifier.isPublic(modifiers)) { // properties.put(field.getName(), new FieldProperty(field)); // } else { // inaccessableFieldsExist = true; // } // } // } // } // break; // } // if (properties.isEmpty() && inaccessableFieldsExist) { // throw new YAMLException("No JavaBean properties found in " + type.getName()); // } propertiesCache.put(type, properties); return properties; } //public Set<Property> getProperties(Class<? extends Object> type) throws IntrospectionException { public Set<Property> getProperties(Class<? extends Object> type) { return getProperties(type, beanAccess); } // public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess) // throws IntrospectionException { public Set<Property> getProperties(Class<? extends Object> type, BeanAccess bAccess) { if (readableProperties.containsKey(type)) { return readableProperties.get(type); } Set<Property> properties = createPropertySet(type, bAccess); readableProperties.put(type, properties); return properties; } // protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess) // throws IntrospectionException { protected Set<Property> createPropertySet(Class<? extends Object> type, BeanAccess bAccess) { Set<Property> properties = new TreeSet<Property>(); Collection<Property> props = getPropertiesMap(type, bAccess).values(); for (Property property : props) { if (property.isReadable() && (allowReadOnlyProperties || property.isWritable())) { properties.add(property); } } return properties; } // public Property getProperty(Class<? extends Object> type, String name) // throws IntrospectionException { public Property getProperty(Class<? extends Object> type, String name) { return getProperty(type, name, beanAccess); } // public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess) // throws IntrospectionException { public Property getProperty(Class<? extends Object> type, String name, BeanAccess bAccess) { Map<String, Property> properties = getPropertiesMap(type, bAccess); Property property = properties.get(name); if (property == null && skipMissingProperties) { property = new MissingProperty(name); } if (property == null || !property.isWritable()) { throw new YAMLException("Unable to find property '" + name + "' on class: " + type.getName()); } return property; } public void setBeanAccess(BeanAccess beanAccess) { if (this.beanAccess != beanAccess) { this.beanAccess = beanAccess; propertiesCache.clear(); readableProperties.clear(); } } public void setAllowReadOnlyProperties(boolean allowReadOnlyProperties) { if (this.allowReadOnlyProperties != allowReadOnlyProperties) { this.allowReadOnlyProperties = allowReadOnlyProperties; readableProperties.clear(); } } /** * Skip properties that are missing during deserialization of YAML to a Java * object. The default is false. * * @param skipMissingProperties true if missing properties should be skipped, false otherwise. */ public void setSkipMissingProperties(boolean skipMissingProperties) { if (this.skipMissingProperties != skipMissingProperties) { this.skipMissingProperties = skipMissingProperties; readableProperties.clear(); } } }