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

Thymeleaf 3.0 Fragment Expression is giving error #165

Closed
esaruhan opened this issue Nov 28, 2017 · 3 comments
Closed

Thymeleaf 3.0 Fragment Expression is giving error #165

esaruhan opened this issue Nov 28, 2017 · 3 comments
Assignees

Comments

@esaruhan
Copy link

esaruhan commented Nov 28, 2017

When it try to use thymeleaf-layout-dialect and flexible layout fragment expression, it gives error .

To implement this i created a project named ThymeleafExamples on github.

Resource : **8.3 Flexible layouts: beyond mere fragment insertion ** ( http://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#fragment-specification-syntax )

Scenario : I would like to use thymeleaf layout dialect, i can use it without fragment expression.
But when i use this with fragment expression and thymeleaf layout dialect i get an error.

The problem occurs when i insert the code below into Template3.html

<head th:fragment="common_header(title,links)">

I m using this in content page like this

<head th:replace="Template3 :: common_header(~{::title},~{::link})">

Content3.html

/~https://github.com/esaruhan/ThymeleafExamples/blob/master/src/main/resources/templates/Content3.html

Template3.html

/~https://github.com/esaruhan/ThymeleafExamples/blob/master/src/main/resources/templates/Template3.html

I am getting this error :

java.lang.StackOverflowError: null
	at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936) ~[na:1.8.0_121]
	at org.apache.catalina.connector.Request.getAttribute(Request.java:892) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
	at org.apache.catalina.connector.RequestFacade.getAttribute(RequestFacade.java:282) ~[tomcat-embed-core-8.5.23.jar:8.5.23]
	at org.thymeleaf.context.WebEngineContext$RequestAttributesVariablesMap.getVariable(WebEngineContext.java:695) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.context.WebEngineContext.getVariable(WebEngineContext.java:194) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.spring4.expression.SPELContextMapWrapper.get(SPELContextMapWrapper.java:128) ~[thymeleaf-spring4-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.springframework.context.expression.MapAccessor.read(MapAccessor.java:52) ~[spring-context-4.3.12.RELEASE.jar:4.3.12.RELEASE]
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:189) ~[spring-expression-4.3.12.RELEASE.jar:4.3.12.RELEASE]
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:94) ~[spring-expression-4.3.12.RELEASE.jar:4.3.12.RELEASE]
	at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:81) ~[spring-expression-4.3.12.RELEASE.jar:4.3.12.RELEASE]
	at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:121) ~[spring-expression-4.3.12.RELEASE.jar:4.3.12.RELEASE]
	at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:324) ~[spring-expression-4.3.12.RELEASE.jar:4.3.12.RELEASE]
	at org.thymeleaf.spring4.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:263) ~[thymeleaf-spring4-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:165) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.standard.expression.FragmentExpression.createExecutedFragmentExpression(FragmentExpression.java:432) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.computeFragment(AbstractStandardFragmentInsertionTagProcessor.java:347) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.standard.processor.AbstractStandardFragmentInsertionTagProcessor.doProcess(AbstractStandardFragmentInsertionTagProcessor.java:110) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.Model.process(Model.java:282) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1587) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.Model.process(Model.java:282) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1587) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.Model.process(Model.java:282) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1587) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.Model.process(Model.java:282) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1587) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.Model.process(Model.java:282) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1587) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
	at org.thymeleaf.engine.Model.process(Model.java:282) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
@ultraq
Copy link
Owner

ultraq commented Nov 29, 2017

Hi @esaruhan, I haven't debugged the code with your example templates yet (thanks for creating examples I can use to test against by the way 👍), but my gut is telling me the errors you're getting are because you're trying to mix 2 layout methods on a key element, the <head> element.

Because it's such a common scenario, the layout dialect automatically merges the elements of your <head> templates when instructed to decorate another template. This makes needing th:replace processors on or inside the <head> element unnecessary, instead relying on a few merging strategies to bind everything together (https://ultraq.github.io/thymeleaf-layout-dialect/Configuration.html#head-element-merging).

However, by putting th:replace to manually instruct Thymeleaf to do what the layout dialect is already doing (possibly causing a re-processing of elements and for the layout dialect and Thymeleaf to fight over the <head> element), this is likely the cause of this error.

As you've already stated, you can use the layout dialect without the additional th:replace (and in fact the templates looks a lot simpler with it too):

Template3.html

<head>
  <!-- Common styles and scripts -->
  <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}"/>
</head>

Content3.html

<head>
  <title>DEĞİŞTİRİLDİ TITTILE</title>
  <meta charset="UTF-8">
  <link rel="stylesheet" type="text/css" th:href="@{/resources/css/first.css}" >
  <link rel="stylesheet" type="text/css" th:href="@{/resources/css/second.css}" >
  <link rel="stylesheet" type="text/css" th:href="@{/resources/css/fourth.css}" >
</head>

Result:

<head>
  <title>DEĞİŞTİRİLDİ TITTILE</title>
  <!-- Common styles and scripts -->
  <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}"/>
  <meta charset="UTF-8">
  <link rel="stylesheet" type="text/css" th:href="@{/resources/css/first.css}" >
  <link rel="stylesheet" type="text/css" th:href="@{/resources/css/second.css}" >
  <link rel="stylesheet" type="text/css" th:href="@{/resources/css/fourth.css}" >
</head>

I'll get some time to eventually debug the code with your examples, but is there some reason you're trying to mix these 2 layout methods together? (I'm trying to understand what your use case might be.)

@esaruhan
Copy link
Author

esaruhan commented Nov 29, 2017

Thanks for replying.

I would like to use this dialect for the flexibility to design the layout as its main aim. But also i would like use fragment expression for adding extra fragments or not .

Actually i should not try this both scenarios for head, as you mention about head tag its behaviours is different.

My use case is :
I organize my admin template under this layout dialect but i will have some extra css ,javascript files for pages. I would like to use fragment expression to add extra css,javascript files. But pages also can not have extra files, at this time i should pass empty ( ~{} ) or no-operation fragment expression. It gives me flexibility. when i use layout:fragment in template page, i have to use it as it is or change it completely in content page. But i need a different scenario, i should add different things (css,fragment etc) (with using fragment expressions) to fragment without changing it completely. Maybe there can be many ways to solve my use case but i would like to use it both mixed if possible.

@ultraq ultraq added this to the Layout Dialect 2.4 milestone Feb 11, 2018
@ultraq ultraq self-assigned this Mar 21, 2019
ultraq added a commit that referenced this issue Mar 29, 2019
@ultraq
Copy link
Owner

ultraq commented Mar 30, 2019

I've added an extra option that can be passed to the layout dialect during setup to tell it to disable the automatic <head> merging so that things like the th:replace in this issue can be run without conflict. I'm not entirely sure if that will help as it's been so long since this issue was raised and so I'm missing some of the context of the time, so I'm adding the words "experimental" around it to try convey that it still needs work. From my testing it allows th:replace to work without encountering the StackOverflowError that was reported, so hoping that's a step in the right direction.

Using the configuration option has been added to the docs: https://ultraq.github.io/thymeleaf-layout-dialect/Configuration.html

This is now available in 2.4.0-SNAPSHOT.

@ultraq ultraq closed this as completed Mar 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants