001/*
002 * Copyright 2002-2014 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.expression.spel.ast;
018
019import java.util.ArrayList;
020import java.util.LinkedList;
021import java.util.List;
022
023import org.springframework.expression.PropertyAccessor;
024
025/**
026 * Utilities methods for use in the Ast classes.
027 *
028 * @author Andy Clement
029 * @since 3.0.2
030 */
031public abstract class AstUtils {
032
033        /**
034         * Determines the set of property resolvers that should be used to try and access a
035         * property on the specified target type. The resolvers are considered to be in an
036         * ordered list, however in the returned list any that are exact matches for the input
037         * target type (as opposed to 'general' resolvers that could work for any type) are
038         * placed at the start of the list. In addition, there are specific resolvers that
039         * exactly name the class in question and resolvers that name a specific class but it
040         * is a supertype of the class we have. These are put at the end of the specific resolvers
041         * set and will be tried after exactly matching accessors but before generic accessors.
042         * @param targetType the type upon which property access is being attempted
043         * @return a list of resolvers that should be tried in order to access the property
044         */
045        public static List<PropertyAccessor> getPropertyAccessorsToTry(
046                        Class<?> targetType, List<PropertyAccessor> propertyAccessors) {
047
048                List<PropertyAccessor> specificAccessors = new ArrayList<PropertyAccessor>();
049                List<PropertyAccessor> generalAccessors = new ArrayList<PropertyAccessor>();
050                for (PropertyAccessor resolver : propertyAccessors) {
051                        Class<?>[] targets = resolver.getSpecificTargetClasses();
052                        if (targets == null) {  // generic resolver that says it can be used for any type
053                                generalAccessors.add(resolver);
054                        }
055                        else {
056                                if (targetType != null) {
057                                        int pos = 0;
058                                        for (Class<?> clazz : targets) {
059                                                if (clazz == targetType) {  // put exact matches on the front to be tried first?
060                                                        specificAccessors.add(pos++, resolver);
061                                                }
062                                                else if (clazz.isAssignableFrom(targetType)) {  // put supertype matches at the end of the
063                                                        // specificAccessor list
064                                                        generalAccessors.add(resolver);
065                                                }
066                                        }
067                                }
068                        }
069                }
070                List<PropertyAccessor> resolvers = new LinkedList<PropertyAccessor>();
071                resolvers.addAll(specificAccessors);
072                resolvers.addAll(generalAccessors);
073                return resolvers;
074        }
075
076}