Skip to content

Commit

Permalink
Document StandardTypeLocator configuration to support user types
Browse files Browse the repository at this point in the history
Prior to this commit, it was unclear to users and third parties that it
is necessary to manually configure a StandardTypeLocator with a
specific ClassLoader to ensure that the SpEL expression parser is able
to reliably locate user types.

For example, the StandardBeanExpressionResolver in the spring-context
module configures a StandardTypeLocator using the bean ClassLoader of
the corresponding BeanFactory.

This commit improves the documentation to raise awareness of this fact.

Closes spring-projectsgh-26253
  • Loading branch information
sbrannen committed Sep 8, 2023
1 parent 1227fe5 commit 10de295
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,15 @@ Kotlin::
----
======

[NOTE]
====
If your application or framework manages its own `EvaluationContext`, you may need to
manually configure a `StandardTypeLocator` with a specific `ClassLoader` to ensure that
the SpEL expression parser is able to reliably locate user types.
For example, the `StandardBeanExpressionResolver` in the `spring-context` module
configures a `StandardTypeLocator` using the bean `ClassLoader` of the corresponding
`BeanFactory`.
====


Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2023 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.
Expand Down Expand Up @@ -39,12 +39,17 @@

/**
* A powerful and highly configurable {@link EvaluationContext} implementation.
* This context uses standard implementations of all applicable strategies,
* based on reflection to resolve properties, methods and fields.
*
* <p>For a simpler builder-style context variant for data-binding purposes,
* <p>This context uses standard implementations of all applicable strategies,
* based on reflection to resolve properties, methods, and fields. Note, however,
* that you may need to manually configure a {@code StandardTypeLocator} with a
* specific {@link ClassLoader} to ensure that the SpEL expression parser is able
* to reliably locate user types. See {@link #setTypeLocator(TypeLocator)} for
* details.
*
* <p>For a simpler, builder-style context variant for data-binding purposes,
* consider using {@link SimpleEvaluationContext} instead which allows for
* opting into several SpEL features as needed by specific evaluation cases.
* opting into several SpEL features as needed by specific use cases.
*
* @author Andy Clement
* @author Juergen Hoeller
Expand Down Expand Up @@ -182,11 +187,29 @@ public BeanResolver getBeanResolver() {
return this.beanResolver;
}

/**
* Set the {@link TypeLocator} to use to find types, either by short or
* fully-qualified name.
* <p>By default, a {@link StandardTypeLocator} will be used.
* <p><strong>NOTE</strong>: Even if a {@code StandardTypeLocator} is
* sufficient, you may need to manually configure a {@code StandardTypeLocator}
* with a specific {@link ClassLoader} to ensure that the SpEL expression
* parser is able to reliably locate user types.
* @param typeLocator the {@code TypeLocator} to use
* @see StandardTypeLocator#StandardTypeLocator(ClassLoader)
* @see #getTypeLocator()
*/
public void setTypeLocator(TypeLocator typeLocator) {
Assert.notNull(typeLocator, "TypeLocator must not be null");
this.typeLocator = typeLocator;
}

/**
* Get the configured {@link TypeLocator} that will be used to find types,
* either by short or fully-qualified name.
* <p>See {@link #setTypeLocator(TypeLocator)} for further details.
* @see #setTypeLocator(TypeLocator)
*/
@Override
public TypeLocator getTypeLocator() {
if (this.typeLocator == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@

/**
* A simple implementation of {@link TypeLocator} that uses the default
* {@link ClassLoader} or a supplied {@link ClassLoader} to locate types.
* {@link #StandardTypeLocator() ClassLoader} or a supplied
* {@link #StandardTypeLocator(ClassLoader) ClassLoader} to locate types.
*
* <p>Supports <em>well-known</em> packages, registered as
* {@linkplain #registerImport(String) import prefixes}. If a type cannot be found,
Expand All @@ -51,6 +52,9 @@ public class StandardTypeLocator implements TypeLocator {
/**
* Create a {@code StandardTypeLocator} for the default {@link ClassLoader}
* (typically, the thread context {@code ClassLoader}).
* <p>Favor {@link #StandardTypeLocator(ClassLoader)} over this constructor
* in order to provide a specific {@link ClassLoader} that is able to reliably
* locate user types.
* @see ClassUtils#getDefaultClassLoader()
*/
public StandardTypeLocator() {
Expand All @@ -59,6 +63,9 @@ public StandardTypeLocator() {

/**
* Create a {@code StandardTypeLocator} for the given {@link ClassLoader}.
* <p>Favor this constructor over {@link #StandardTypeLocator()} in order
* to provide a specific {@link ClassLoader} that is able to reliably locate
* user types.
* @param classLoader the {@code ClassLoader} to delegate to
*/
public StandardTypeLocator(@Nullable ClassLoader classLoader) {
Expand Down

0 comments on commit 10de295

Please sign in to comment.