| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.codehaus.groovy.ast.tools; |
| |
| import org.codehaus.groovy.ast.ClassHelper; |
| import org.codehaus.groovy.ast.ClassNode; |
| import org.codehaus.groovy.ast.MethodNode; |
| import org.codehaus.groovy.ast.PropertyNode; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import static java.beans.Introspector.decapitalize; |
| |
| public class BeanUtils { |
| static final String GET_PREFIX = "get"; |
| static final String IS_PREFIX = "is"; |
| |
| /** |
| * Get all properties including JavaBean pseudo properties matching getter conventions. |
| * |
| * @param type the ClassNode |
| * @param includeSuperProperties whether to include super properties |
| * @param includeStatic whether to include static properties |
| * @param includePseudoGetters whether to include JavaBean pseudo (getXXX/isYYY) properties with no corresponding field |
| * @return the list of found property nodes |
| */ |
| public static List<PropertyNode> getAllProperties(ClassNode type, boolean includeSuperProperties, boolean includeStatic, boolean includePseudoGetters) { |
| // TODO add generics support so this can be used for @EAHC |
| // TODO add an includePseudoSetters so this can be used for @TupleConstructor |
| ClassNode node = type; |
| List<PropertyNode> result = new ArrayList<PropertyNode>(); |
| Set<String> names = new HashSet<String>(); |
| while (node != null) { |
| addExplicitProperties(node, result, names, includeStatic); |
| if (!includeSuperProperties) break; |
| node = node.getSuperClass(); |
| } |
| addPseudoProperties(type, result, names, includeStatic, includePseudoGetters, includeSuperProperties); |
| return result; |
| } |
| |
| private static void addExplicitProperties(ClassNode cNode, List<PropertyNode> result, Set<String> names, boolean includeStatic) { |
| for (PropertyNode pNode : cNode.getProperties()) { |
| if (includeStatic || !pNode.isStatic()) { |
| if (!names.contains(pNode.getName())) { |
| result.add(pNode); |
| names.add(pNode.getName()); |
| } |
| } |
| } |
| } |
| |
| private static void addPseudoProperties(ClassNode cNode, List<PropertyNode> result, Set<String> names, boolean includeStatic, boolean includePseudoGetters, boolean includeSuperProperties) { |
| if (!includePseudoGetters) return; |
| List<MethodNode> methods = cNode.getAllDeclaredMethods(); |
| ClassNode node = cNode.getSuperClass(); |
| if (includeSuperProperties) { |
| while (node != null) { |
| for (MethodNode next : node.getAllDeclaredMethods()) { |
| if (!next.isPrivate()) { |
| methods.add(next); |
| } |
| } |
| node = node.getSuperClass(); |
| } |
| } |
| for (MethodNode mNode : methods) { |
| if (!includeStatic && mNode.isStatic()) continue; |
| String name = mNode.getName(); |
| if ((name.length() <= 3 && !name.startsWith(IS_PREFIX)) || name.equals("getClass") || name.equals("getMetaClass") || name.equals("getDeclaringClass")) { |
| // Optimization: skip invalid propertyNames |
| continue; |
| } |
| if (mNode.getDeclaringClass() != cNode && mNode.isPrivate()) { |
| // skip private super methods |
| continue; |
| } |
| int paramCount = mNode.getParameters().length; |
| ClassNode returnType = mNode.getReturnType(); |
| if (paramCount == 0) { |
| if (name.startsWith(GET_PREFIX)) { |
| // Simple getter |
| String propName = decapitalize(name.substring(3)); |
| if (!names.contains(propName)) { |
| result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null)); |
| names.add(propName); |
| } |
| } else { |
| if (name.startsWith(IS_PREFIX) && returnType.equals(ClassHelper.boolean_TYPE)) { |
| // boolean getter |
| String propName = decapitalize(name.substring(2)); |
| if (!names.contains(propName)) { |
| names.add(propName); |
| result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, mNode.getCode(), null)); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |