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.beans.factory.access.el; 018 019import java.beans.FeatureDescriptor; 020import java.util.Iterator; 021import javax.el.ELContext; 022import javax.el.ELException; 023import javax.el.ELResolver; 024import javax.el.PropertyNotWritableException; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028 029import org.springframework.beans.factory.BeanFactory; 030 031/** 032 * Unified EL {@code ELResolver} that delegates to a Spring BeanFactory, 033 * resolving name references to Spring-defined beans. 034 * 035 * @author Juergen Hoeller 036 * @since 2.5.2 037 * @see org.springframework.web.jsf.el.SpringBeanFacesELResolver 038 */ 039public abstract class SpringBeanELResolver extends ELResolver { 040 041 /** Logger available to subclasses */ 042 protected final Log logger = LogFactory.getLog(getClass()); 043 044 045 @Override 046 public Object getValue(ELContext elContext, Object base, Object property) throws ELException { 047 if (base == null) { 048 String beanName = property.toString(); 049 BeanFactory bf = getBeanFactory(elContext); 050 if (bf.containsBean(beanName)) { 051 if (logger.isTraceEnabled()) { 052 logger.trace("Successfully resolved variable '" + beanName + "' in Spring BeanFactory"); 053 } 054 elContext.setPropertyResolved(true); 055 return bf.getBean(beanName); 056 } 057 } 058 return null; 059 } 060 061 @Override 062 public Class<?> getType(ELContext elContext, Object base, Object property) throws ELException { 063 if (base == null) { 064 String beanName = property.toString(); 065 BeanFactory bf = getBeanFactory(elContext); 066 if (bf.containsBean(beanName)) { 067 elContext.setPropertyResolved(true); 068 return bf.getType(beanName); 069 } 070 } 071 return null; 072 } 073 074 @Override 075 public void setValue(ELContext elContext, Object base, Object property, Object value) throws ELException { 076 if (base == null) { 077 String beanName = property.toString(); 078 BeanFactory bf = getBeanFactory(elContext); 079 if (bf.containsBean(beanName)) { 080 if (value == bf.getBean(beanName)) { 081 // Setting the bean reference to the same value is alright - can simply be ignored... 082 elContext.setPropertyResolved(true); 083 } 084 else { 085 throw new PropertyNotWritableException( 086 "Variable '" + beanName + "' refers to a Spring bean which by definition is not writable"); 087 } 088 } 089 } 090 } 091 092 @Override 093 public boolean isReadOnly(ELContext elContext, Object base, Object property) throws ELException { 094 if (base == null) { 095 String beanName = property.toString(); 096 BeanFactory bf = getBeanFactory(elContext); 097 if (bf.containsBean(beanName)) { 098 return true; 099 } 100 } 101 return false; 102 } 103 104 @Override 105 public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext elContext, Object base) { 106 return null; 107 } 108 109 @Override 110 public Class<?> getCommonPropertyType(ELContext elContext, Object base) { 111 return Object.class; 112 } 113 114 115 /** 116 * Retrieve the Spring BeanFactory to delegate bean name resolution to. 117 * @param elContext the current ELContext 118 * @return the Spring BeanFactory (never {@code null}) 119 */ 120 protected abstract BeanFactory getBeanFactory(ELContext elContext); 121 122}