All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.beans.factory.config.FieldRetrievingFactoryBean Maven / Gradle / Ivy

There is a newer version: 6.1.6
Show newest version
/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed 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
 *
 *      https://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.springframework.beans.factory.config;

import java.lang.reflect.Field;

import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;

/**
 * {@link FactoryBean} which retrieves a static or non-static field value.
 *
 * 

Typically used for retrieving public static final constants. Usage example: * *

 * // standard definition for exposing a static field, specifying the "staticField" property
 * <bean id="myField" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
 *   <property name="staticField" value="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
 * </bean>
 *
 * // convenience version that specifies a static field pattern as bean name
 * <bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE"
 *       class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>
 * 
* *

If you are using Spring 2.0, you can also use the following style of configuration for * public static fields. * *

<util:constant static-field="java.sql.Connection.TRANSACTION_SERIALIZABLE"/>
* * @author Juergen Hoeller * @since 1.1 * @see #setStaticField */ public class FieldRetrievingFactoryBean implements FactoryBean, BeanNameAware, BeanClassLoaderAware, InitializingBean { @Nullable private Class targetClass; @Nullable private Object targetObject; @Nullable private String targetField; @Nullable private String staticField; @Nullable private String beanName; @Nullable private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); // the field we will retrieve @Nullable private Field fieldObject; /** * Set the target class on which the field is defined. * Only necessary when the target field is static; else, * a target object needs to be specified anyway. * @see #setTargetObject * @see #setTargetField */ public void setTargetClass(@Nullable Class targetClass) { this.targetClass = targetClass; } /** * Return the target class on which the field is defined. */ @Nullable public Class getTargetClass() { return this.targetClass; } /** * Set the target object on which the field is defined. * Only necessary when the target field is not static; * else, a target class is sufficient. * @see #setTargetClass * @see #setTargetField */ public void setTargetObject(@Nullable Object targetObject) { this.targetObject = targetObject; } /** * Return the target object on which the field is defined. */ @Nullable public Object getTargetObject() { return this.targetObject; } /** * Set the name of the field to be retrieved. * Refers to either a static field or a non-static field, * depending on a target object being set. * @see #setTargetClass * @see #setTargetObject */ public void setTargetField(@Nullable String targetField) { this.targetField = (targetField != null ? StringUtils.trimAllWhitespace(targetField) : null); } /** * Return the name of the field to be retrieved. */ @Nullable public String getTargetField() { return this.targetField; } /** * Set a fully qualified static field name to retrieve, * e.g. "example.MyExampleClass.MY_EXAMPLE_FIELD". * Convenient alternative to specifying targetClass and targetField. * @see #setTargetClass * @see #setTargetField */ public void setStaticField(String staticField) { this.staticField = StringUtils.trimAllWhitespace(staticField); } /** * The bean name of this FieldRetrievingFactoryBean will be interpreted * as "staticField" pattern, if neither "targetClass" nor "targetObject" * nor "targetField" have been specified. * This allows for concise bean definitions with just an id/name. */ @Override public void setBeanName(String beanName) { this.beanName = StringUtils.trimAllWhitespace(BeanFactoryUtils.originalBeanName(beanName)); } @Override public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } @Override public void afterPropertiesSet() throws ClassNotFoundException, NoSuchFieldException { if (this.targetClass != null && this.targetObject != null) { throw new IllegalArgumentException("Specify either targetClass or targetObject, not both"); } if (this.targetClass == null && this.targetObject == null) { if (this.targetField != null) { throw new IllegalArgumentException( "Specify targetClass or targetObject in combination with targetField"); } // If no other property specified, consider bean name as static field expression. if (this.staticField == null) { this.staticField = this.beanName; Assert.state(this.staticField != null, "No target field specified"); } // Try to parse static field into class and field. int lastDotIndex = this.staticField.lastIndexOf('.'); if (lastDotIndex == -1 || lastDotIndex == this.staticField.length()) { throw new IllegalArgumentException( "staticField must be a fully qualified class plus static field name: " + "e.g. 'example.MyExampleClass.MY_EXAMPLE_FIELD'"); } String className = this.staticField.substring(0, lastDotIndex); String fieldName = this.staticField.substring(lastDotIndex + 1); this.targetClass = ClassUtils.forName(className, this.beanClassLoader); this.targetField = fieldName; } else if (this.targetField == null) { // Either targetClass or targetObject specified. throw new IllegalArgumentException("targetField is required"); } // Try to get the exact method first. Class targetClass = (this.targetObject != null ? this.targetObject.getClass() : this.targetClass); this.fieldObject = targetClass.getField(this.targetField); } @Override @Nullable public Object getObject() throws IllegalAccessException { if (this.fieldObject == null) { throw new FactoryBeanNotInitializedException(); } ReflectionUtils.makeAccessible(this.fieldObject); if (this.targetObject != null) { // instance field return this.fieldObject.get(this.targetObject); } else { // class field return this.fieldObject.get(null); } } @Override public Class getObjectType() { return (this.fieldObject != null ? this.fieldObject.getType() : null); } @Override public boolean isSingleton() { return false; } }