Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SpEL T() operator not able to locate user types with default StandardTypeLocator configuration #26253

Closed
jjpianta opened this issue Dec 10, 2020 · 7 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: documentation A documentation task
Milestone

Comments

@jjpianta
Copy link

jjpianta commented Dec 10, 2020

Hi,
we are experiencing such a strange behavior using SPEL T() operator to get references to custom enums or types in our thymeleaf templates: everything goes straight till we get random failures in resolving our custom types.
"random" means that same expression sometimes get parsed properly and sometimes don't.
It looks like failures occur only in asynch context (StreamingResponseBody's callbacks and @‌Asynch annotated methods)

Same issue submitted to the Thymeleaf team

org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "myVar == T(my.custom.TypeEnum).VALUE)" (template: "myTemplate" - line xx, col yy)
        at org.thymeleaf.spring4.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290) ~[thymeleaf-spring4-3.0.11.RELEASE.jar:3.0.11.RELEASE]
        at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
        at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
 ...
        at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:592) ~[thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) [thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1059) [thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
        at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1048) [thymeleaf-3.0.11.RELEASE.jar:3.0.11.RELEASE]
...
        at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115) [spring-aop-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_201]
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1005E: Type cannot be found 'my.custom.TypeEnum'
        at org.springframework.expression.spel.support.StandardTypeLocator.findType(StandardTypeLocator.java:115) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ExpressionState.findType(ExpressionState.java:154) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.TypeReference.getValueInternal(TypeReference.java:64) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:52) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:88) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.OpEQ.getValueInternal(OpEQ.java:43) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.OpEQ.getValueInternal(OpEQ.java:32) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:169) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.OpAnd.getBooleanValue(OpAnd.java:56) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.OpAnd.getValueInternal(OpAnd.java:51) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:169) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.Ternary.getValueInternal(Ternary.java:51) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:119) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:327) ~[spring-expression-4.3.29.RELEASE.jar:4.3.29.RELEASE]
        at org.thymeleaf.spring4.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:263) ~[thymeleaf-spring4-3.0.11.RELEASE.jar:3.0.11.RELEASE]
        ... 53 more

see full stack trace

  • Environment
    • java 1.8.0_201-b09
    • tomcat 8.5.39
    • thymeleaf-3.0.11.RELEASE.jar
    • thymeleaf-spring4-3.0.11.RELEASE.jar
    • spring-aop-4.3.29.RELEASE.jar
    • spring-aspects-4.3.29.RELEASE.jar
    • spring-beans-4.3.29.RELEASE.jar
    • spring-context-4.3.29.RELEASE.jar
    • spring-context-support-4.3.29.RELEASE.jar
    • spring-core-4.3.29.RELEASE.jar
    • spring-expression-4.3.29.RELEASE.jar
    • spring-jdbc-4.3.29.RELEASE.jar
    • spring-jms-4.3.29.RELEASE.jar
    • spring-messaging-4.3.29.RELEASE.jar
    • spring-orm-4.3.29.RELEASE.jar
    • spring-security-acl-4.2.19.RELEASE.jar
    • spring-security-config-4.2.19.RELEASE.jar
    • spring-security-core-4.2.19.RELEASE.jar
    • spring-security-oauth-2.4.0.RELEASE.jar
    • spring-security-openid-4.2.19.RELEASE.jar
    • spring-security-taglibs-4.2.19.RELEASE.jar
    • spring-security-web-4.2.19.RELEASE.jar
    • spring-tx-4.3.29.RELEASE.jar
    • spring-web-4.3.29.RELEASE.jar
    • spring-webmvc-4.3.29.RELEASE.jar
@mqueb
Copy link

mqueb commented Mar 31, 2021

got the same bug.

my Cacheable:

@Cacheable(value = "myValue", key = "#myKey", cacheManager = "myManager",
            unless = "#result.erreur != null && #result.erreur.myEnumValue == T(com.xxx.MyEnum).YYY")

work fine calling it without async.....

but if done with

CompletableFuture.supplyAsync(() -> my function())

Error :

2021-03-31T09:22:34.248-04:00 [APP/PROC/WEB/0] [OUT] {"@timestamp":"2021-03-31T13:22:34.247+00:00","@Version":1,"message":"Une erreur technique est survenue lors de l'appel \u00E0 InformationTelephoneGateway.","logger_name":"com.xxx.MyServiceimpl","thread_name":"ForkJoinPool.commonPool-worker-1","level":"ERROR","level_value":40000,"stack_trace":"org.springframework.expression.spel.SpelEvaluationException: EL1005E: Type cannot be found 'com.xxx.MyEnum'\n\tat org.springframework.expression.spel.support.StandardTypeLocator.findType(StandardTypeLocator.java:117)\n\tat org.springframework.expression.spel.ExpressionState.findType(ExpressionState.java:155)\n\tat org.springframework.expression.spel.ast.TypeReference.getValueInternal(TypeReference.java:69)\n\tat org.springframework.expression.spel.ast.CompoundExpression.getValueRef(CompoundExpression.java:55)\n\tat org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:91)\n\tat org.springframework.expression.spel.ast.OpEQ.getValueInternal(OpEQ.java:43)\n\tat org.springframework.expression.spel.ast.OpEQ.getValueInternal(OpEQ.java:32)\n\tat org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:188)\n\tat org.springframework.expression.spel.ast.OpAnd.getBooleanValue(OpAnd.java:57)\n\tat org.springframework.expression.spel.ast.OpAnd.getValueInternal(OpAnd.java:52)\n\tat org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:117)\n\tat org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:308)\n\tat org.springframework.cache.interceptor.CacheOperationExpressionEvaluator.unless(CacheOperationExpressionEvaluator.java:113)\n\tat org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.canPutToCache(CacheAspectSupport.java:783)\n\tat org.springframework.cache.interceptor.CacheAspectSupport$CachePutRequest.apply(CacheAspectSupport.java:835)\n\tat org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:430)\n\tat org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:346)\n\tat org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\n\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\n\tat org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95)\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\n\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)\n\tat org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)\n\tat

stupid workarround:

@Cacheable(value = "infoTelephones", key = "#numeroTelephone", cacheManager = "infoTelephonesCacheManager",
            unless = "#result.notCacheable")

and move the test in the method added on the object...

@jjpianta
Copy link
Author

jjpianta commented Apr 1, 2021

It turned out it was an issue with StandardTypeLocator used by Thymeleaf Context: dunno why, but sometimes it gets created with System classloader, so it can't resolve our app types.
We made a dirty fix supplying a TypeLocator initialized with our web app's classloader

		Context ctx = new Context(locale);
		StandardEvaluationContext delegate = new StandardEvaluationContext();
		StandardTypeLocator tl = new StandardTypeLocator(MyClass.class.getClassLoader());
		delegate.setTypeLocator(tl);
		EvaluationContext evaluationContext = new ThymeleafEvaluationContextWrapper(delegate);
		
		
		ctx.setVariable(ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME,
				evaluationContext);

@rstoyanchev rstoyanchev added the in: web Issues in web modules (web, webmvc, webflux, websocket) label Nov 8, 2021
@vvvinamer
Copy link

Hey @jjpianta, have we got any updates regarding this? Can this be solved without some dirty work around?

@jjpianta
Copy link
Author

jjpianta commented May 17, 2022 via email

@VuKrampHub
Copy link

I still run into this as of 2023 with java 18 + spring boot 2.7.7 (spring framework 5.3.24)

@sbrannen sbrannen changed the title Random SpelEvaluationException with T() operator - EL1005E: Type cannot be found Random SpelEvaluationException with T() operator - EL1005E: Type cannot be found Jul 19, 2023
@sbrannen sbrannen changed the title Random SpelEvaluationException with T() operator - EL1005E: Type cannot be found SpEL T() operator not able to locate user types with default StandardTypeLocator configuration Jul 19, 2023
@sbrannen
Copy link
Member

We made a dirty fix supplying a TypeLocator initialized with our web app's classloader

I don't necessarily consider that a "dirty fix" but rather a robust solution.

The SpEL expression parser needs to be able to reliably locate user types, and providing a suitable ClassLoader serves that purpose.

@sbrannen sbrannen self-assigned this Jul 19, 2023
@sbrannen sbrannen added type: documentation A documentation task in: core Issues in core modules (aop, beans, core, context, expression) and removed status: waiting-for-triage An issue we've not yet triaged or decided on in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jul 19, 2023
@sbrannen sbrannen added this to the 6.0.12 milestone Jul 19, 2023
@sbrannen
Copy link
Member

sbrannen commented Sep 8, 2023

This issue has been repurposed to improve the documentation regarding proper configuration of the StandardTypeLocator.

See 10de295 for details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: documentation A documentation task
Projects
None yet
Development

No branches or pull requests

7 participants