简体   繁体   中英

OGNL Exception using Thymeleaf

I'm trying to use a list of enum in thymeleaf and i'm facing a OGNL Exception problem each time i attempt to get attribute of the enum Using basic loop like this

<th:block th:each="item : ${summary}">
                <li href="'#' + ${item.anchor}">
                    <div th:text=${item.title}></div>
                </li>
            </th:block>

Summary is a list of enum, my enum looks like this

public enum FollowupPdfSummaryEnum {
   COVER("coverAnchor", "templates/firstPageInclude.html", "Couverture", FollowupBlocEnum.COVER_PAGE),
   SUMMARY("summaryAnchor", "templates/summaryInclude.html", "Sommaire"),
   SITUATION_PLAN("situationPlanAnchor", "templates/situationPlanInclude.html", "Plan de situation", FollowupBlocEnum.SITUATION_PLAN),
   BUILDING_VISUAL("buildingVisualAnchor", "templates/visualInclude.html", "Visuels", FollowupBlocEnum.BUILDING_VISUAL),
   HEALTH_BOOK("healthBookAnchor", "templates/healthBookBatInclude.html", "Carnet de santé", FollowupBlocEnum.HEALTH_BOOK),
   IDENTITY_CARD("identityCardAnchor", "templates/identityCardInclude.html", "Fiche d'identité", FollowupBlocEnum.IDENTITY_CARD),
   COUNTER_SITUATION_PLAN("counterSituationAnchor", "templates/counterSituationPlanInclude.html", "Plan des compteurs", FollowupBlocEnum.COUNTER_SITUATION_PLAN),
   DANGEROUS_MATERIAL("dangerousMaterialAnchor", "templates/dangerousMaterialInclude.html", "Diagnostic Matières Dangereuses", FollowupBlocEnum.DANGEROUS_MATERIAL_DIAGNOSIS),
   RECAP_WORK_TODO("workDoneAnchor", "templates/workTodoListInclude.html", "Récapitulatif des travaux à réaliser", FollowupBlocEnum.WORK_DONE_REPORT),
   VISIT_REPORT("visitReportAnchor", "templates/visitReportInclude.html", "Rapport de visite", FollowupBlocEnum.VISIT_REPORT),
   VISIT_REPORT_OCCUPATION("visitReportOccupationAnchor", "templates/occupationVisitReportInclude.html", "Rapport de visite : Occupations", FollowupBlocEnum.OCCUPATION_VISIT_REPORT),
   ANNEXE("annexeAnchor", "templates/annexeInclude.html", "Annexes");
   
   private final String anchor;
   private final String path;
   private final String title;
   private final FollowupBlocEnum block;
   
   private FollowupPdfSummaryEnum(String anchor, String path, String title, FollowupBlocEnum block) {
      this.anchor = anchor;
      this.path = path;
      this.title = title;
      this.block = block;
   }
   private FollowupPdfSummaryEnum(String anchor, String path, String title) {
      this.anchor = anchor;
      this.path = path;
      this.title = title;
      this.block = null;
   }

   public String getPath() {
      return path;
   }
   public String getTitle() {
      return title;
   }
   public FollowupBlocEnum getBlock() {
      return block;
   }
   public String getAnchor() {
      return anchor;
   }
}

here's the stack trace

2022-07-15 13:58:22,359 ERROR [http-bio-8080-exec-15] [org.thymeleaf.TemplateEngine : 1136] - [THYMELEAF][http-bio-8080-exec-15] Exception processing template "followUpExport.html": Exception evaluating OGNL expression: "item.title" (template: "templates/summaryInclude.html" - line 26, col 11)
org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating OGNL expression: "item.title" (template: "templates/summaryInclude.html" - line 26, col 11)
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:201)
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:105)
    at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166)
    at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66)
    at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109)
    at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138)
    at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144)
    at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74)
    at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95)
    at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633)
    at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314)
    at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205)
    at org.thymeleaf.engine.Model.process(Model.java:282)
    at org.thymeleaf.engine.Model.process(Model.java:290)
    at org.thymeleaf.engine.IteratedGatheringModelProcessable.processIterationModel(IteratedGatheringModelProcessable.java:367)
    at org.thymeleaf.engine.IteratedGatheringModelProcessable.process(IteratedGatheringModelProcessable.java:221)
    at org.thymeleaf.engine.ProcessorTemplateHandler.handleCloseElement(ProcessorTemplateHandler.java:1640)
    at org.thymeleaf.engine.CloseElementTag.beHandled(CloseElementTag.java:139)
    at org.thymeleaf.engine.Model.process(Model.java:282)
    at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1587)
    at org.thymeleaf.engine.OpenElementTag.beHandled(OpenElementTag.java:205)
    at org.thymeleaf.engine.TemplateModel.process(TemplateModel.java:136)
    at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:661)
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098)
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1059)
    at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1048)
    at fr.bluepad.site.back.util.pdf.PdfGenerator.parseHtmlThymeLeafToString(PdfGenerator.java:50)
    at fr.bluepad.site.back.util.pdf.PdfGenerator.generatePdf(PdfGenerator.java:28)
    at fr.bluepad.site.back.service.followup.impl.FollowupCreationPdfServiceImpl.generateFollowupBatPdf(FollowupCreationPdfServiceImpl.java:143)
    at fr.bluepad.site.back.service.followup.impl.FollowupCreationPdfServiceImpl.generateFollowupBatPdf(FollowupCreationPdfServiceImpl.java:49)
    at fr.bluepad.site.front.actions.clients.followup.FollowupAuditAction.downloadPreviewPdf(FollowupAuditAction.java:148)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:871)
    at ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1294)
    at ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
    at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethodWithDebugInfo(XWorkMethodAccessor.java:117)
    at com.opensymphony.xwork2.ognl.accessor.XWorkMethodAccessor.callMethod(XWorkMethodAccessor.java:108)
    at ognl.OgnlRuntime.callMethod(OgnlRuntime.java:1370)
    at ognl.ASTMethod.getValueBody(ASTMethod.java:91)
    at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
    at ognl.SimpleNode.getValue(SimpleNode.java:258)
    at ognl.Ognl.getValue(Ognl.java:467)
    at ognl.Ognl.getValue(Ognl.java:431)
    at com.opensymphony.xwork2.ognl.OgnlUtil$3.execute(OgnlUtil.java:352)
    at com.opensymphony.xwork2.ognl.OgnlUtil.compileAndExecuteMethod(OgnlUtil.java:404)
    at com.opensymphony.xwork2.ognl.OgnlUtil.callMethod(OgnlUtil.java:350)
    at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:430)
    at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:290)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:251)
    at org.apache.struts2.interceptor.DeprecationInterceptor.intercept(DeprecationInterceptor.java:41)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:168)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
    at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:76)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:229)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at org.apache.struts2.interceptor.DateTextFieldInterceptor.intercept(DateTextFieldInterceptor.java:125)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:253)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
    at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:140)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
    at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:245)
    at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
    at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:575)
    at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
    at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:165)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:1025)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:452)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1195)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:654)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:319)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:744)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating OGNL expression: "item.title"
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:201)
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:187)
    ... 118 more
Caused by: java.lang.UnsupportedOperationException
    at java.util.AbstractMap.put(AbstractMap.java:209)
    at ognl.OgnlContext.put(OgnlContext.java:579)
    at com.opensymphony.xwork2.ognl.accessor.ObjectAccessor.getProperty(ObjectAccessor.java:19)
    at ognl.OgnlRuntime.getProperty(OgnlRuntime.java:2417)
    at ognl.ASTProperty.getValueBody(ASTProperty.java:114)
    at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
    at ognl.SimpleNode.getValue(SimpleNode.java:258)
    at ognl.ASTChain.getValueBody(ASTChain.java:141)
    at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
    at ognl.SimpleNode.getValue(SimpleNode.java:258)
    at ognl.Ognl.getValue(Ognl.java:467)
    at ognl.Ognl.getValue(Ognl.java:431)
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.executeExpression(OGNLVariableExpressionEvaluator.java:336)
    at org.thymeleaf.standard.expression.OGNLVariableExpressionEvaluator.evaluate(OGNLVariableExpressionEvaluator.java:180)
    ... 119 more

i populate my hashmap variables with the summary list this way

private ByteArrayInputStream generateFollowupBatPdf(FollowupAuditStruct auditStruct) {
      //generate pdf 
      String pathHtml = "followUpExport.html";
      String baseuri = "/";
      
   // Summary
      List<FollowupPdfSummaryEnum> summary = new ArrayList<>();
      summary.add(FollowupPdfSummaryEnum.COVER);
      summary.add(FollowupPdfSummaryEnum.SUMMARY);
      summary.add(FollowupPdfSummaryEnum.SITUATION_PLAN);
      summary.add(FollowupPdfSummaryEnum.BUILDING_VISUAL);
      variables.put("summary", summary);

      try (
              ByteArrayOutputStream outputStream = (ByteArrayOutputStream) PdfGenerator.generatePdf(pathHtml, baseuri, variables);
      ){
         return new ByteArrayInputStream(outputStream.toByteArray());
      } catch (IOException e) {
          System.out.println("Error : " + e);
      }
      return null;
   }

I don't understand what is an OGNL Exception neither how to solve it

Here is my code, as mentioned in my comment in the question:

For reference, here is the comment:

The problem is probably hidden in PdfGenerator.generatePdf. I can take your enum and your Thymeleaf template and I can generate a PDF successfully using your data and my own PdfRendererBuilder. First I generate the rendered HTML as a string (using Thymeleaf's TemplateEngine) and then I use the PDF generator. Bottom line: Your enum and Thymeleaf are correct (except for the fact that you cannot actually put a href attribute inside a li element - the href will have no effect).

Here is the Thymeleaf renderer code and PDF generator code:

// imports include:
// import org.thymeleaf.TemplateEngine;
// import org.thymeleaf.context.Context;

model.put("summary", summary);

TemplateEngine templateEngine = ThymeleafConfig.templateEngine();
Context thymeleafCtx = new Context();
thymeleafCtx.setVariable("summary", summary);
String html = templateEngine.process("enum_to_pdf.html", thymeleafCtx);
        
try (OutputStream os = new FileOutputStream("C:/temp/out.pdf")) {
    PdfRendererBuilder builder = new PdfRendererBuilder();
    builder.useFastMode();
    builder.withHtmlContent(html, null);
    builder.toStream(os);
    builder.run();
}

The ThymeleafConfig.templateEngine() is a static helper method I use:

public static TemplateEngine templateEngine() {
    TemplateEngine templateEngine = new TemplateEngine();
    //templateEngine.addDialect(new Java8TimeDialect());
    templateEngine.addTemplateResolver(htmlTemplateResolver());
    return templateEngine;
}

This, in turn, uses the following (you may want to place your template somewhere else with a different resolver):

public static ITemplateResolver htmlTemplateResolver() {
    ClassLoaderTemplateResolver templateResolver
            = new ClassLoaderTemplateResolver(Thread
                    .currentThread().getContextClassLoader());
    templateResolver.setTemplateMode(TemplateMode.HTML);
    templateResolver.setPrefix("/thymeleaf/");
    templateResolver.setSuffix(".html");
    templateResolver.setCharacterEncoding("UTF-8");
    return templateResolver;
}

My full Thymeleaf template:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
    <head>
    </head>

    <body>

        <th:block th:each="item : ${summary}">
            <li href="'#' + ${item.anchor}">
                <div th:text=${item.title}></div>
            </li>
        </th:block>

    </body>
</html>

The end result:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM