spring-projects/spring-framework · error · IllegalArgumentException

staticField must be a fully qualified class plus static…

Error message

staticField must be a fully qualified class plus static field name: for example, 'example.MyExampleClass.MY_EXAMPLE_FIELD'

What it means

Thrown as an IllegalArgumentException by FieldRetrievingFactoryBean.afterPropertiesSet when staticField does not contain a '.' separating the class name from the field name, or the dot is the last character. The factory parses staticField as 'fullyQualifiedClassName.fieldName' via lastIndexOf('.'); if there is no dot or no name after it, the split is impossible and the configuration is rejected with an explicit example.

Solutions

  1. Set staticField to the full 'package.Class.FIELD' form, e.g. 'com.acme.Const.MAX'.
  2. If the bean id itself is the full expression, ensure it contains the package, class, and field separated by dots.
  3. If you only have a field name, also set targetClass (or targetObject) and targetField instead of staticField.
  4. Log/inspect the actual staticField value at runtime to catch placeholder or whitespace corruption.

Example fix

<!-- before: bare field name, no class -->
<bean id='f' class='o.s.b.f.config.FieldRetrievingFactoryBean'>
  <property name='staticField' value='MAX'/>
</bean>

<!-- after: fully qualified class plus field -->
<bean id='f' class='o.s.b.f.config.FieldRetrievingFactoryBean'>
  <property name='staticField' value='com.acme.Const.MAX'/>
</bean>
Defensive patterns

Strategy: validation

Validate before calling

String sf = fb.getStaticField();
int dot = (sf == null) ? -1 : sf.lastIndexOf('.');
if (dot <= 0 || dot == sf.length() - 1) {
    throw new IllegalArgumentException("staticField must be 'pkg.Cls.FIELD': " + sf);
}

Type guard

// True if staticField has a class portion and a non-empty field name
boolean wellFormed(String sf) {
    int dot = sf == null ? -1 : sf.lastIndexOf('.');
    return dot > 0 && dot < sf.length() - 1;
}

Prevention

When it happens

Trigger: Setting staticField to a value with no '.' (e.g. just 'MAX' or a bare bean name without package), or ending with '.' (e.g. 'com.acme.Const.'). The factory enters the parse branch (no targetClass/targetObject, no targetField) and the lastIndexOf('.') check fails.

Common situations: Passing a short bean id like 'MAX' as staticField assuming it resolves; typo dropping the package portion; trailing dot from concatenation bugs; copy-paste that included only the field name; misconfigured PropertyPlaceholder producing an empty package portion.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/20b13fa8b8cfdf2b. Report an issue: GitHub.

Appendix: source

Thrown at spring-beans/src/main/java/org/springframework/beans/factory/config/FieldRetrievingFactoryBean.java:182

			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: " +
						"for example, '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);
	}

View on GitHub (pinned to 69bf83ad71)