-1

I'm working on my new Java + Spring + Thymeleaf project. So today I've got a very strange message from thymeleaf:

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'session' available as request attribute

You know, it is really strange. According to thymeleaf documentation https://www.thymeleaf.org/doc/articles/springmvcaccessdata.html (chapter 3):

Similarly to the request parameters, session attributes can be access by using the session. prefix:
    <p th:text="${session.mySessionAttribute}" th:unless="${session == null}">[...]</p>

So, ok. I've tried another way:

Or by using #session, that gives you direct access to the javax.servlet.http.HttpSession object: ${#session.getAttribute('mySessionAttribute')}

And got the exception:

java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name '#session' available as request attribute

I didn't find any solutions of this problem on google. So, it's time to show you some code. Controller mapping:

@Controller
@RequestMapping("/admin")
public class AdminController {
@GetMapping("/addPost")
    public String addPost(HttpSession session, Model model) {
        session.setAttribute("post", new Post());
        return "admin/add-post";
    }

    @PostMapping("/addPost")
    public String processAddPost(HttpSession session) {
        Post post = (Post)session.getAttribute("post");
        try {
            postService.addPost(post);
        } catch (Exception ignore) {}
        session.removeAttribute("post");
        return "redirect:/admin/listPosts";
    }
...
}

Piece of HTML page(displayed on GET request to /admin/addPost):

<form 
        th:action="@{/admin/previewPost}" 
        th:object="${session.post}" 
        method="post">
        <input 
            id="post_name_input"
            placeholder="Post name" 
            th:field="*{name}" />
        <br>

        <textarea
            id="post_description_textarea"
            class="wide-input"
            placeholder="Post content" 
            th:field="*{description}" />
        <br>
        <button type="submit">Create</button>
    </form>

What am I doing wrong? Maybe, there is a bug in thymeleaf? My build.gradle:

buildscript {
    repositories {
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath 'com.bmuschko:gradle-tomcat-plugin:2.4.1'
    }
}

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'com.bmuschko.tomcat'

compileJava.options.encoding = 'UTF-8'

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

def tomcatVersion = '9.0.22'
dependencies {
    testImplementation 'junit:junit:4.12'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
            "org.apache.tomcat.embed:tomcat-embed-logging-juli:8.5.2",
            "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"

    testCompile group: 'org.hamcrest', name: 'hamcrest-all', version: '1.3'
    testCompile group: 'org.mockito', name: 'mockito-all', version: '1.8.4'
}

tomcat {
    httpProtocol = 'org.apache.coyote.http11.Http11Nio2Protocol'
    ajpProtocol  = 'org.apache.coyote.ajp.AjpNio2Protocol'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.apache.tomcat:tomcat-dbcp:9.0.22'
    implementation 'org.postgresql:postgresql:42.2.6'
    implementation 'org.springframework:spring-context:5.1.8.RELEASE'
    implementation 'org.springframework:spring-webmvc:5.1.8.RELEASE'
    implementation 'org.springframework:spring-orm:5.1.8.RELEASE'
    implementation 'org.springframework:spring-tx:5.1.8.RELEASE'
    implementation 'org.springframework:spring-aspects:5.1.8.RELEASE'
    implementation 'org.hibernate:hibernate-core:5.4.1.Final'
    implementation 'org.springframework.security:spring-security-core:5.1.5.RELEASE'
    implementation 'org.springframework.security:spring-security-web:5.1.5.RELEASE'
    implementation 'org.springframework.security:spring-security-config:5.1.5.RELEASE'
    implementation 'org.springframework.data:spring-data-jpa:2.1.10.RELEASE'
    implementation 'javax.servlet:servlet-api:2.5' 
    implementation 'org.hibernate.validator:hibernate-validator:6.0.2.Final'
    implementation 'org.hibernate.validator:hibernate-validator-annotation-processor:6.0.2.Final'
    implementation 'org.thymeleaf:thymeleaf:3.0.11.RELEASE'
    implementation 'org.thymeleaf:thymeleaf-spring5:3.0.11.RELEASE'
    implementation 'org.aspectj:aspectjrt:1.5.4'
    implementation 'org.apache.logging.log4j:log4j-api:2.8.2'
    implementation 'org.apache.logging.log4j:log4j-core:2.8.2'

}

UPD: This answer was marked as duplicated. But it is not. I've tried all solutions in the referenced question and they didn't work for me. The main difference is that it seems in my case there is no 'session' object in thymeleaf context.

Levon Minasian
  • 531
  • 1
  • 5
  • 17
  • Possible duplicate of [Accessing session attributes in Thymeleaf templates](https://stackoverflow.com/questions/20632134/accessing-session-attributes-in-thymeleaf-templates) – Ghasem Sadeghi Aug 31 '19 at 16:31
  • ``` org.springframework.expression.spel.SpelEvaluationException: EL1011E: Method call: Attempted to call method getAttribute(java.lang.String) on null context object ``` – Levon Minasian Aug 31 '19 at 16:40
  • @ЛевонМинасян Can you check my answer? And give a response about your result. – Avijit Barua Sep 02 '19 at 10:50
  • @ЛевонМинасян You haven't gave any reply! – Avijit Barua Sep 03 '19 at 04:21

1 Answers1

1

First, let me correct you. With get controller when you redirect to a page where you need to submit a form you need to send a model object. But Instesd you are putting in session.setAttribute("post", new Post()). So first you have to modify your get controller like

@GetMapping("/addPost")
public String addPost(Model model) {
    model.addAttribute("post", new Post());
    return "admin/add-post";
}

And your html form should be like this

<form 
        th:action="@{/admin/addPost}" 
        th:object="${post}" 
        method="post">
        <input 
            id="post_name_input"
            placeholder="Post name" 
            th:field="*{name}" />
        <br>

        <textarea
            id="post_description_textarea"
            class="wide-input"
            placeholder="Post content" 
            th:field="*{description}" />
        <br>
        <button type="submit">Create</button>
    </form>

Now you need to modify your post controller to save post object. In order to do so modify your post controller like

   @PostMapping("/addPost")
    public String processAddPost(@ModelAttribute("post") Post post,  HttpSession session) {
         session.setAttribute("post", post);
         postService.addPost(post);
         return "redirect:/admin/listPosts";
    }

In this controller you are using postService but you haven't autowired your postService. So autowired postService in this controller. Hope this will work.

If you want to put value in session then use

session.setAttribute("post", post);

this line. And in any case if you want to retrieve session data then you can use statement

Post post = (Post)session.getAttribute("post");

Note: Please give a response whether you got your expected result or not.

Avijit Barua
  • 2,950
  • 5
  • 14
  • 35