package com.loohp.limbo.Utils; import java.beans.FeatureDescriptor; 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.LinkedHashSet; import java.util.Map; import java.util.Set; import org.yaml.snakeyaml.error.YAMLException; import org.yaml.snakeyaml.introspector.BeanAccess; import org.yaml.snakeyaml.introspector.FieldProperty; import org.yaml.snakeyaml.introspector.MethodProperty; import org.yaml.snakeyaml.introspector.MissingProperty; import org.yaml.snakeyaml.introspector.Property; import org.yaml.snakeyaml.introspector.PropertyUtils; import org.yaml.snakeyaml.util.PlatformFeatureDetector; public class YamlOrder extends PropertyUtils { private final Map, Map> propertiesCache = new HashMap, Map>(); private final Map, Set> readableProperties = new HashMap, Set>(); private BeanAccess beanAccess = BeanAccess.DEFAULT; private boolean allowReadOnlyProperties = false; private boolean skipMissingProperties = false; private PlatformFeatureDetector platformFeatureDetector; public YamlOrder() { this(new PlatformFeatureDetector()); } YamlOrder(PlatformFeatureDetector platformFeatureDetector) { this.platformFeatureDetector = platformFeatureDetector; if (platformFeatureDetector.isRunningOnAndroid()) { beanAccess = BeanAccess.FIELD; } } protected Map getPropertiesMap(Class type, BeanAccess bAccess) { if (propertiesCache.containsKey(type)) { return propertiesCache.get(type); } Map properties = new LinkedHashMap(); 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)); } } } break; default: try { for (PropertyDescriptor property : Introspector.getBeanInfo(type) .getPropertyDescriptors()) { Method readMethod = property.getReadMethod(); if ((readMethod == null || !readMethod.getName().equals("getClass")) && !isTransient(property)) { properties.put(property.getName(), new MethodProperty(property)); } } } catch (IntrospectionException e) { throw new YAMLException(e); } 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()); } System.out.println(properties); propertiesCache.put(type, properties); return properties; } private static final String TRANSIENT = "transient"; private boolean isTransient(FeatureDescriptor fd) { return Boolean.TRUE.equals(fd.getValue(TRANSIENT)); } public Set getProperties(Class type) { return getProperties(type, beanAccess); } public Set getProperties(Class type, BeanAccess bAccess) { if (readableProperties.containsKey(type)) { return readableProperties.get(type); } Set properties = createPropertySet(type, bAccess); readableProperties.put(type, properties); return properties; } protected Set createPropertySet(Class type, BeanAccess bAccess) { Set properties = new LinkedHashSet<>(); Collection props = getPropertiesMap(type, bAccess).values(); for (Property property : props) { if (property.isReadable() && (allowReadOnlyProperties || property.isWritable())) { properties.add(property); } } return properties; } public Property getProperty(Class type, String name) { return getProperty(type, name, beanAccess); } public Property getProperty(Class type, String name, BeanAccess bAccess) { Map properties = getPropertiesMap(type, bAccess); Property property = properties.get(name); if (property == null && skipMissingProperties) { property = new MissingProperty(name); } if (property == null) { throw new YAMLException( "Unable to find property '" + name + "' on class: " + type.getName()); } return property; } public void setBeanAccess(BeanAccess beanAccess) { if (platformFeatureDetector.isRunningOnAndroid() && beanAccess != BeanAccess.FIELD) { throw new IllegalArgumentException( "JVM is Android - only BeanAccess.FIELD is available"); } 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(); } } public boolean isAllowReadOnlyProperties() { return allowReadOnlyProperties; } public void setSkipMissingProperties(boolean skipMissingProperties) { if (this.skipMissingProperties != skipMissingProperties) { this.skipMissingProperties = skipMissingProperties; readableProperties.clear(); } } public boolean isSkipMissingProperties() { return skipMissingProperties; } }