001/* 002 * Copyright 2002-2017 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.support; 018 019import java.util.Collections; 020import java.util.LinkedList; 021import java.util.List; 022 023import org.springframework.expression.EvaluationException; 024import org.springframework.expression.TypeLocator; 025import org.springframework.expression.spel.SpelEvaluationException; 026import org.springframework.expression.spel.SpelMessage; 027import org.springframework.lang.Nullable; 028import org.springframework.util.ClassUtils; 029 030/** 031 * A simple implementation of {@link TypeLocator} that uses the context ClassLoader 032 * (or any ClassLoader set upon it). It supports 'well-known' packages: So if a 033 * type cannot be found, it will try the registered imports to locate it. 034 * 035 * @author Andy Clement 036 * @author Juergen Hoeller 037 * @since 3.0 038 */ 039public class StandardTypeLocator implements TypeLocator { 040 041 @Nullable 042 private final ClassLoader classLoader; 043 044 private final List<String> knownPackagePrefixes = new LinkedList<>(); 045 046 047 /** 048 * Create a StandardTypeLocator for the default ClassLoader 049 * (typically, the thread context ClassLoader). 050 */ 051 public StandardTypeLocator() { 052 this(ClassUtils.getDefaultClassLoader()); 053 } 054 055 /** 056 * Create a StandardTypeLocator for the given ClassLoader. 057 * @param classLoader the ClassLoader to delegate to 058 */ 059 public StandardTypeLocator(@Nullable ClassLoader classLoader) { 060 this.classLoader = classLoader; 061 // Similar to when writing regular Java code, it only knows about java.lang by default 062 registerImport("java.lang"); 063 } 064 065 066 /** 067 * Register a new import prefix that will be used when searching for unqualified types. 068 * Expected format is something like "java.lang". 069 * @param prefix the prefix to register 070 */ 071 public void registerImport(String prefix) { 072 this.knownPackagePrefixes.add(prefix); 073 } 074 075 /** 076 * Remove that specified prefix from this locator's list of imports. 077 * @param prefix the prefix to remove 078 */ 079 public void removeImport(String prefix) { 080 this.knownPackagePrefixes.remove(prefix); 081 } 082 083 /** 084 * Return a list of all the import prefixes registered with this StandardTypeLocator. 085 * @return a list of registered import prefixes 086 */ 087 public List<String> getImportPrefixes() { 088 return Collections.unmodifiableList(this.knownPackagePrefixes); 089 } 090 091 092 /** 093 * Find a (possibly unqualified) type reference - first using the type name as-is, 094 * then trying any registered prefixes if the type name cannot be found. 095 * @param typeName the type to locate 096 * @return the class object for the type 097 * @throws EvaluationException if the type cannot be found 098 */ 099 @Override 100 public Class<?> findType(String typeName) throws EvaluationException { 101 String nameToLookup = typeName; 102 try { 103 return ClassUtils.forName(nameToLookup, this.classLoader); 104 } 105 catch (ClassNotFoundException ey) { 106 // try any registered prefixes before giving up 107 } 108 for (String prefix : this.knownPackagePrefixes) { 109 try { 110 nameToLookup = prefix + '.' + typeName; 111 return ClassUtils.forName(nameToLookup, this.classLoader); 112 } 113 catch (ClassNotFoundException ex) { 114 // might be a different prefix 115 } 116 } 117 throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName); 118 } 119 120}